77mod logger;
88mod 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
1216use lsp_server:: Connection ;
1317use 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