Skip to content

Commit 7bcb4c2

Browse files
committed
Auto merge of rust-lang#14689 - Veykril:patch-vscode-paths, r=Veykril
fix: Force InitializeParams windows path drives to uppercase Should fix rust-lang/rust-analyzer#14683 cc `@jyn514`
2 parents 83cc5ef + 1edcefb commit 7bcb4c2

File tree

1 file changed

+60
-11
lines changed
  • crates/rust-analyzer/src/bin

1 file changed

+60
-11
lines changed

crates/rust-analyzer/src/bin/main.rs

+60-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
mod logger;
88
mod rustc_wrapper;
99

10-
use std::{env, fs, path::Path, process};
10+
use std::{
11+
env, fs,
12+
path::{Path, PathBuf},
13+
process,
14+
};
1115

1216
use lsp_server::Connection;
1317
use rust_analyzer::{cli::flags, config::Config, from_json, Result};
@@ -149,12 +153,18 @@ fn run_server() -> Result<()> {
149153

150154
let (initialize_id, initialize_params) = connection.initialize_start()?;
151155
tracing::info!("InitializeParams: {}", initialize_params);
152-
let initialize_params =
153-
from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
154-
155-
let root_path = match initialize_params
156-
.root_uri
156+
let lsp_types::InitializeParams {
157+
root_uri,
158+
capabilities,
159+
workspace_folders,
160+
initialization_options,
161+
client_info,
162+
..
163+
} = from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
164+
165+
let root_path = match root_uri
157166
.and_then(|it| it.to_file_path().ok())
167+
.map(patch_path_prefix)
158168
.and_then(|it| AbsPathBuf::try_from(it).ok())
159169
{
160170
Some(it) => it,
@@ -164,19 +174,19 @@ fn run_server() -> Result<()> {
164174
}
165175
};
166176

167-
let workspace_roots = initialize_params
168-
.workspace_folders
177+
let workspace_roots = workspace_folders
169178
.map(|workspaces| {
170179
workspaces
171180
.into_iter()
172181
.filter_map(|it| it.uri.to_file_path().ok())
182+
.map(patch_path_prefix)
173183
.filter_map(|it| AbsPathBuf::try_from(it).ok())
174184
.collect::<Vec<_>>()
175185
})
176186
.filter(|workspaces| !workspaces.is_empty())
177187
.unwrap_or_else(|| vec![root_path.clone()]);
178-
let mut config = Config::new(root_path, initialize_params.capabilities, workspace_roots);
179-
if let Some(json) = initialize_params.initialization_options {
188+
let mut config = Config::new(root_path, capabilities, workspace_roots);
189+
if let Some(json) = initialization_options {
180190
if let Err(e) = config.update(json) {
181191
use lsp_types::{
182192
notification::{Notification, ShowMessage},
@@ -205,7 +215,7 @@ fn run_server() -> Result<()> {
205215

206216
connection.initialize_finish(initialize_id, initialize_result)?;
207217

208-
if let Some(client_info) = initialize_params.client_info {
218+
if let Some(client_info) = client_info {
209219
tracing::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default());
210220
}
211221

@@ -219,3 +229,42 @@ fn run_server() -> Result<()> {
219229
tracing::info!("server did shut down");
220230
Ok(())
221231
}
232+
233+
fn patch_path_prefix(path: PathBuf) -> PathBuf {
234+
use std::path::{Component, Prefix};
235+
if cfg!(windows) {
236+
// VSCode might report paths with the file drive in lowercase, but this can mess
237+
// with env vars set by tools and build scripts executed by r-a such that it invalidates
238+
// cargo's compilations unnecessarily. https://github.com/rust-lang/rust-analyzer/issues/14683
239+
// So we just uppercase the drive letter here unconditionally.
240+
// (doing it conditionally is a pain because std::path::Prefix always reports uppercase letters on windows)
241+
let mut comps = path.components();
242+
match comps.next() {
243+
Some(Component::Prefix(prefix)) => {
244+
let prefix = match prefix.kind() {
245+
Prefix::Disk(d) => {
246+
format!("{}:", d.to_ascii_uppercase() as char)
247+
}
248+
Prefix::VerbatimDisk(d) => {
249+
format!(r"\\?\{}:\", d.to_ascii_uppercase() as char)
250+
}
251+
_ => return path,
252+
};
253+
let mut path = PathBuf::new();
254+
path.push(prefix);
255+
path.extend(comps);
256+
path
257+
}
258+
_ => path,
259+
}
260+
} else {
261+
path
262+
}
263+
}
264+
265+
#[test]
266+
#[cfg(windows)]
267+
fn patch_path_prefix_works() {
268+
assert_eq!(patch_path_prefix(r"c:\foo\bar".into()), PathBuf::from(r"C:\foo\bar"));
269+
assert_eq!(patch_path_prefix(r"\\?\c:\foo\bar".into()), PathBuf::from(r"\\?\C:\foo\bar"));
270+
}

0 commit comments

Comments
 (0)