Unnamed repository; edit this file 'description' to name the repository.
-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 9b416d1ef0..b255a44053 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"));
+}