7
7
mod logger;
8
8
mod rustc_wrapper;
9
9
10
- use std:: { env, fs, path:: Path , process} ;
10
+ use std:: {
11
+ env, fs,
12
+ path:: { Path , PathBuf } ,
13
+ process,
14
+ } ;
11
15
12
16
use lsp_server:: Connection ;
13
17
use rust_analyzer:: { cli:: flags, config:: Config , from_json, Result } ;
@@ -149,12 +153,18 @@ fn run_server() -> Result<()> {
149
153
150
154
let ( initialize_id, initialize_params) = connection. initialize_start ( ) ?;
151
155
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
157
166
. and_then ( |it| it. to_file_path ( ) . ok ( ) )
167
+ . map ( patch_path_prefix)
158
168
. and_then ( |it| AbsPathBuf :: try_from ( it) . ok ( ) )
159
169
{
160
170
Some ( it) => it,
@@ -164,19 +174,19 @@ fn run_server() -> Result<()> {
164
174
}
165
175
} ;
166
176
167
- let workspace_roots = initialize_params
168
- . workspace_folders
177
+ let workspace_roots = workspace_folders
169
178
. map ( |workspaces| {
170
179
workspaces
171
180
. into_iter ( )
172
181
. filter_map ( |it| it. uri . to_file_path ( ) . ok ( ) )
182
+ . map ( patch_path_prefix)
173
183
. filter_map ( |it| AbsPathBuf :: try_from ( it) . ok ( ) )
174
184
. collect :: < Vec < _ > > ( )
175
185
} )
176
186
. filter ( |workspaces| !workspaces. is_empty ( ) )
177
187
. 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 {
180
190
if let Err ( e) = config. update ( json) {
181
191
use lsp_types:: {
182
192
notification:: { Notification , ShowMessage } ,
@@ -205,7 +215,7 @@ fn run_server() -> Result<()> {
205
215
206
216
connection. initialize_finish ( initialize_id, initialize_result) ?;
207
217
208
- if let Some ( client_info) = initialize_params . client_info {
218
+ if let Some ( client_info) = client_info {
209
219
tracing:: info!( "Client '{}' {}" , client_info. name, client_info. version. unwrap_or_default( ) ) ;
210
220
}
211
221
@@ -219,3 +229,42 @@ fn run_server() -> Result<()> {
219
229
tracing:: info!( "server did shut down" ) ;
220
230
Ok ( ( ) )
221
231
}
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