about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-29 18:14:42 +0000
committerbors <bors@rust-lang.org>2023-04-29 18:14:42 +0000
commit7bcb4c2ef23e151a639ff918fbb8ab9d521eabb9 (patch)
treec5420c3c935c1c546566ea81b132c38b63312ab8
parent83cc5ef4c1c455b42ebbdac877a657f15c70b5fa (diff)
parent1edcefb6859069cebf8abef16f8c069912f273e9 (diff)
Auto merge of #14689 - Veykril:patch-vscode-paths, r=Veykril
fix: Force InitializeParams windows path drives to uppercase

Should fix https://github.com/rust-lang/rust-analyzer/issues/14683
cc `@jyn514`
-rw-r--r--crates/rust-analyzer/src/bin/main.rs71
1 files changed, 60 insertions, 11 deletions
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 9b416d1ef00..b255a440538 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -7,7 +7,11 @@
 mod logger;
 mod rustc_wrapper;
 
-use std::{env, fs, path::Path, process};
+use std::{
+    env, fs,
+    path::{Path, PathBuf},
+    process,
+};
 
 use lsp_server::Connection;
 use rust_analyzer::{cli::flags, config::Config, from_json, Result};
@@ -149,12 +153,18 @@ fn run_server() -> Result<()> {
 
     let (initialize_id, initialize_params) = connection.initialize_start()?;
     tracing::info!("InitializeParams: {}", initialize_params);
-    let initialize_params =
-        from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
-
-    let root_path = match initialize_params
-        .root_uri
+    let lsp_types::InitializeParams {
+        root_uri,
+        capabilities,
+        workspace_folders,
+        initialization_options,
+        client_info,
+        ..
+    } = from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
+
+    let root_path = match root_uri
         .and_then(|it| it.to_file_path().ok())
+        .map(patch_path_prefix)
         .and_then(|it| AbsPathBuf::try_from(it).ok())
     {
         Some(it) => it,
@@ -164,19 +174,19 @@ fn run_server() -> Result<()> {
         }
     };
 
-    let workspace_roots = initialize_params
-        .workspace_folders
+    let workspace_roots = workspace_folders
         .map(|workspaces| {
             workspaces
                 .into_iter()
                 .filter_map(|it| it.uri.to_file_path().ok())
+                .map(patch_path_prefix)
                 .filter_map(|it| AbsPathBuf::try_from(it).ok())
                 .collect::<Vec<_>>()
         })
         .filter(|workspaces| !workspaces.is_empty())
         .unwrap_or_else(|| vec![root_path.clone()]);
-    let mut config = Config::new(root_path, initialize_params.capabilities, workspace_roots);
-    if let Some(json) = initialize_params.initialization_options {
+    let mut config = Config::new(root_path, capabilities, workspace_roots);
+    if let Some(json) = initialization_options {
         if let Err(e) = config.update(json) {
             use lsp_types::{
                 notification::{Notification, ShowMessage},
@@ -205,7 +215,7 @@ fn run_server() -> Result<()> {
 
     connection.initialize_finish(initialize_id, initialize_result)?;
 
-    if let Some(client_info) = initialize_params.client_info {
+    if let Some(client_info) = client_info {
         tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default());
     }
 
@@ -219,3 +229,42 @@ fn run_server() -> Result<()> {
     tracing::info!("server did shut down");
     Ok(())
 }
+
+fn patch_path_prefix(path: PathBuf) -> PathBuf {
+    use std::path::{Component, Prefix};
+    if cfg!(windows) {
+        // VSCode might report paths with the file drive in lowercase, but this can mess
+        // with env vars set by tools and build scripts executed by r-a such that it invalidates
+        // cargo's compilations unnecessarily. https://github.com/rust-lang/rust-analyzer/issues/14683
+        // So we just uppercase the drive letter here unconditionally.
+        // (doing it conditionally is a pain because std::path::Prefix always reports uppercase letters on windows)
+        let mut comps = path.components();
+        match comps.next() {
+            Some(Component::Prefix(prefix)) => {
+                let prefix = match prefix.kind() {
+                    Prefix::Disk(d) => {
+                        format!("{}:", d.to_ascii_uppercase() as char)
+                    }
+                    Prefix::VerbatimDisk(d) => {
+                        format!(r"\\?\{}:\", d.to_ascii_uppercase() as char)
+                    }
+                    _ => return path,
+                };
+                let mut path = PathBuf::new();
+                path.push(prefix);
+                path.extend(comps);
+                path
+            }
+            _ => path,
+        }
+    } else {
+        path
+    }
+}
+
+#[test]
+#[cfg(windows)]
+fn patch_path_prefix_works() {
+    assert_eq!(patch_path_prefix(r"c:\foo\bar".into()), PathBuf::from(r"C:\foo\bar"));
+    assert_eq!(patch_path_prefix(r"\\?\c:\foo\bar".into()), PathBuf::from(r"\\?\C:\foo\bar"));
+}