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`
This commit is contained in:
bors 2023-04-29 18:14:42 +00:00
commit 7bcb4c2ef2

View file

@ -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 lsp_types::InitializeParams {
root_uri,
capabilities,
workspace_folders,
initialization_options,
client_info,
..
} = from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
let root_path = match initialize_params
.root_uri
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"));
}