diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-15 16:35:23 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-15 16:35:23 +0000 |
commit | 4e24b25c669965cf6a68c4b8e775cc83615d978a (patch) | |
tree | 7d44ca9749add5146d0672192d14df9de6c2e730 /crates | |
parent | 4c1b2b921866279d014e377b958112b9e53edc52 (diff) | |
parent | 6fba427bf35bebdc7aa08a241ecbe83a2f725127 (diff) |
Merge #2565
2565: Fixed syntax highlighting not refreshing on windows. r=matklad a=omerbenamram
I was encoutering the same probelm described in #1690.
It seems that events initiated by the frontend with `rust-analyzer/decorationsRequest` would go through.
So whenever a user switches tabs, highlighting will update.
However, when decorations are initiated by a notification with `rust-analyzer/publishDecorations`, it would fail on this check here https://github.com/rust-analyzer/rust-analyzer/blob/6cbd8a4a4bbca8a7656df9f3ef849acebbf9ef9b/editors/code/src/notifications/publish_decorations.ts#L15 (`targetEditor` will always be `undefined`).
This is because it's trying to match the uri `rust-analyzer` sends (which uses an uppercase drive letter) to the uri provided at `editor.document.uri.toString()`, which is both escaped (uses `%3a` for `:`), and uses a lowercase letter drive.
Aparrently this was an issue for some other extensions aswell - https://github.com/Microsoft/vscode/issues/68325.
But this is the defined behavior - https://github.com/microsoft/vscode/blob/c110d84460b3e45842a8fe753562341003595e1d/src/vs/vscode.d.ts#L1304
This fix is only relevant for windows.
I've opted for a server-side fix, since rust will always return uppercase letters for drives, there seems to be no other easy solution than manipulating the Url string before sending it to the frontend.
Closes #1690.
Co-authored-by: Omer Ben-Amram <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_lsp_server/src/world.rs | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index 927449b45..16cc11e8c 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -17,11 +17,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; | |||
17 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; | 17 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; |
18 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; | 18 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; |
19 | use relative_path::RelativePathBuf; | 19 | use relative_path::RelativePathBuf; |
20 | use std::path::{Component, Prefix}; | ||
20 | 21 | ||
21 | use crate::{ | 22 | use crate::{ |
22 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | 23 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, |
23 | LspError, Result, | 24 | LspError, Result, |
24 | }; | 25 | }; |
26 | use std::str::FromStr; | ||
25 | 27 | ||
26 | #[derive(Debug, Clone)] | 28 | #[derive(Debug, Clone)] |
27 | pub struct Options { | 29 | pub struct Options { |
@@ -233,8 +235,8 @@ impl WorldSnapshot { | |||
233 | 235 | ||
234 | pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { | 236 | pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { |
235 | let path = self.vfs.read().file2path(VfsFile(id.0)); | 237 | let path = self.vfs.read().file2path(VfsFile(id.0)); |
236 | let url = Url::from_file_path(&path) | 238 | let url = url_from_path_with_drive_lowercasing(path)?; |
237 | .map_err(|_| format!("can't convert path to url: {}", path.display()))?; | 239 | |
238 | Ok(url) | 240 | Ok(url) |
239 | } | 241 | } |
240 | 242 | ||
@@ -279,3 +281,65 @@ impl WorldSnapshot { | |||
279 | self.analysis.feature_flags() | 281 | self.analysis.feature_flags() |
280 | } | 282 | } |
281 | } | 283 | } |
284 | |||
285 | /// Returns a `Url` object from a given path, will lowercase drive letters if present. | ||
286 | /// This will only happen when processing windows paths. | ||
287 | /// | ||
288 | /// When processing non-windows path, this is essentially the same as `Url::from_file_path`. | ||
289 | fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> { | ||
290 | let component_has_windows_drive = path | ||
291 | .as_ref() | ||
292 | .components() | ||
293 | .find(|comp| { | ||
294 | if let Component::Prefix(c) = comp { | ||
295 | match c.kind() { | ||
296 | Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true, | ||
297 | _ => return false, | ||
298 | } | ||
299 | } | ||
300 | false | ||
301 | }) | ||
302 | .is_some(); | ||
303 | |||
304 | // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters. | ||
305 | if component_has_windows_drive { | ||
306 | let url_original = Url::from_file_path(&path) | ||
307 | .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?; | ||
308 | |||
309 | let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect(); | ||
310 | |||
311 | // There is a drive partition, but we never found a colon. | ||
312 | // This should not happen, but in this case we just pass it through. | ||
313 | if drive_partition.len() == 1 { | ||
314 | return Ok(url_original); | ||
315 | } | ||
316 | |||
317 | let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0]; | ||
318 | let url = Url::from_str(&joined).expect("This came from a valid `Url`"); | ||
319 | |||
320 | Ok(url) | ||
321 | } else { | ||
322 | Ok(Url::from_file_path(&path) | ||
323 | .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | // `Url` is not able to parse windows paths on unix machines. | ||
328 | #[cfg(target_os = "windows")] | ||
329 | #[cfg(test)] | ||
330 | mod path_conversion_windows_tests { | ||
331 | use super::url_from_path_with_drive_lowercasing; | ||
332 | #[test] | ||
333 | fn test_lowercase_drive_letter_with_drive() { | ||
334 | let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap(); | ||
335 | |||
336 | assert_eq!(url.to_string(), "file:///c:/Test"); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn test_drive_without_colon_passthrough() { | ||
341 | let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap(); | ||
342 | |||
343 | assert_eq!(url.to_string(), "file://localhost/C$/my_dir"); | ||
344 | } | ||
345 | } | ||