Skip to content

Commit 4e24b25

Browse files
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 - microsoft/vscode#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]>
2 parents 4c1b2b9 + 6fba427 commit 4e24b25

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed

crates/ra_lsp_server/src/world.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
1717
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
1818
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
1919
use relative_path::RelativePathBuf;
20+
use std::path::{Component, Prefix};
2021

2122
use crate::{
2223
main_loop::pending_requests::{CompletedRequest, LatestRequests},
2324
LspError, Result,
2425
};
26+
use std::str::FromStr;
2527

2628
#[derive(Debug, Clone)]
2729
pub struct Options {
@@ -233,8 +235,8 @@ impl WorldSnapshot {
233235

234236
pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
235237
let path = self.vfs.read().file2path(VfsFile(id.0));
236-
let url = Url::from_file_path(&path)
237-
.map_err(|_| format!("can't convert path to url: {}", path.display()))?;
238+
let url = url_from_path_with_drive_lowercasing(path)?;
239+
238240
Ok(url)
239241
}
240242

@@ -279,3 +281,65 @@ impl WorldSnapshot {
279281
self.analysis.feature_flags()
280282
}
281283
}
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+
}

editors/code/src/notifications/publish_decorations.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ export interface PublishDecorationsParams {
99
}
1010

1111
export function handle(params: PublishDecorationsParams) {
12-
const targetEditor = vscode.window.visibleTextEditors.find(
13-
editor => editor.document.uri.toString() === params.uri,
14-
);
12+
const targetEditor = vscode.window.visibleTextEditors.find(editor => {
13+
const unescapedUri = unescape(editor.document.uri.toString());
14+
// Unescaped URI looks like:
15+
// file:///c:/Workspace/ra-test/src/main.rs
16+
return unescapedUri === params.uri;
17+
});
18+
1519
if (!Server.config.highlightingOn || !targetEditor) {
1620
return;
1721
}
22+
1823
Server.highlighter.setHighlights(targetEditor, params.decorations);
1924
}

0 commit comments

Comments
 (0)