aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_lsp_server/src/world.rs64
1 files changed, 44 insertions, 20 deletions
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index f139a5728..63a820012 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -17,11 +17,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
18use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 18use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
19use relative_path::RelativePathBuf; 19use relative_path::RelativePathBuf;
20use std::path::{Component, Prefix};
20 21
21use crate::{ 22use crate::{
22 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 23 main_loop::pending_requests::{CompletedRequest, LatestRequests},
23 LspError, Result, 24 LspError, Result,
24}; 25};
26use std::str::FromStr;
25 27
26#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
27pub struct Options { 29pub struct Options {
@@ -233,11 +235,8 @@ impl WorldSnapshot {
233 235
234 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { 236 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
235 let path = self.vfs.read().file2path(VfsFile(id.0)); 237 let path = self.vfs.read().file2path(VfsFile(id.0));
236 let url = Url::from_file_path(&path) 238 let url = url_from_path_with_drive_lowercasing(path)?;
237 .map_err(|_| format!("can't convert path to url: {}", path.display()))?;
238 239
239 #[cfg(target_os = "windows")]
240 let url = lowercase_drive_letter(&url);
241 Ok(url) 240 Ok(url)
242 } 241 }
243 242
@@ -283,34 +282,59 @@ impl WorldSnapshot {
283 } 282 }
284} 283}
285 284
286#[cfg(target_os = "windows")] 285/// Returns a `Url` object from a given path, will lowercase drive letters if present.
287fn lowercase_drive_letter(url: &Url) -> Url { 286/// This will only happen when processing windows paths.
288 use std::str::FromStr; 287///
288/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
289fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
290 let component_has_windows_drive = path
291 .as_ref()
292 .components()
293 .find(|comp| {
294 if let Component::Prefix(c) = comp {
295 match c.kind() {
296 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
297 _ => return false,
298 }
299 }
300 false
301 })
302 .is_some();
303
304 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
305 if component_has_windows_drive {
306 let url_original = Url::from_file_path(&path)
307 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
308
309 let drive_partition: Vec<&str> =
310 url_original.as_str().rsplitn(2, ':').collect::<Vec<&str>>();
311
312 // There is a drive partition, but we never found a colon.
313 // This should not happen, but in this case we just pass it through.
314 if drive_partition.len() == 1 {
315 return Ok(url_original);
316 }
289 317
290 let s = url.to_string(); 318 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
291 let drive_partition: Vec<&str> = s.rsplitn(2, ':').collect::<Vec<&str>>(); 319 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
292 320
293 if drive_partition.len() == 1 { 321 Ok(url)
294 return url.clone(); 322 } else {
323 Ok(Url::from_file_path(&path)
324 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
295 } 325 }
296
297 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
298 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
299 url
300} 326}
301 327
302#[test] 328#[test]
303fn test_lowercase_drive_letter_with_drive() { 329fn test_lowercase_drive_letter_with_drive() {
304 let url = Url::from_file_path("C:\\Test").unwrap(); 330 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
305 let url = lowercase_drive_letter(&url);
306 331
307 assert_eq!(url.to_string(), "file:///c:/Test"); 332 assert_eq!(url.to_string(), "file:///c:/Test");
308} 333}
309 334
310#[test] 335#[test]
311fn test_drive_without_colon_passthrough() { 336fn test_drive_without_colon_passthrough() {
312 let url = Url::from_file_path(r#"\\localhost\C$\my_dir"#).expect("Should work"); 337 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
313 let url = lowercase_drive_letter(&url);
314 338
315 assert_eq!(url.to_string(), "file:///C$/my_dir"); 339 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
316} 340}