From 2e2fae32dff6cab508768953bbd34b88b5bea166 Mon Sep 17 00:00:00 2001 From: Omer Ben-Amram Date: Sun, 15 Dec 2019 17:46:00 +0200 Subject: improved path checking to consider only paths that may contain a windows drive. --- crates/ra_lsp_server/src/world.rs | 64 +++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'crates/ra_lsp_server/src/world.rs') 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}; use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; use relative_path::RelativePathBuf; +use std::path::{Component, Prefix}; use crate::{ main_loop::pending_requests::{CompletedRequest, LatestRequests}, LspError, Result, }; +use std::str::FromStr; #[derive(Debug, Clone)] pub struct Options { @@ -233,11 +235,8 @@ impl WorldSnapshot { pub fn file_id_to_uri(&self, id: FileId) -> Result { let path = self.vfs.read().file2path(VfsFile(id.0)); - let url = Url::from_file_path(&path) - .map_err(|_| format!("can't convert path to url: {}", path.display()))?; + let url = url_from_path_with_drive_lowercasing(path)?; - #[cfg(target_os = "windows")] - let url = lowercase_drive_letter(&url); Ok(url) } @@ -283,34 +282,59 @@ impl WorldSnapshot { } } -#[cfg(target_os = "windows")] -fn lowercase_drive_letter(url: &Url) -> Url { - use std::str::FromStr; +/// Returns a `Url` object from a given path, will lowercase drive letters if present. +/// This will only happen when processing windows paths. +/// +/// When processing non-windows path, this is essentially the same as `Url::from_file_path`. +fn url_from_path_with_drive_lowercasing(path: impl AsRef) -> Result { + let component_has_windows_drive = path + .as_ref() + .components() + .find(|comp| { + if let Component::Prefix(c) = comp { + match c.kind() { + Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true, + _ => return false, + } + } + false + }) + .is_some(); + + // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters. + if component_has_windows_drive { + let url_original = Url::from_file_path(&path) + .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?; + + let drive_partition: Vec<&str> = + url_original.as_str().rsplitn(2, ':').collect::>(); + + // There is a drive partition, but we never found a colon. + // This should not happen, but in this case we just pass it through. + if drive_partition.len() == 1 { + return Ok(url_original); + } - let s = url.to_string(); - let drive_partition: Vec<&str> = s.rsplitn(2, ':').collect::>(); + let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0]; + let url = Url::from_str(&joined).expect("This came from a valid `Url`"); - if drive_partition.len() == 1 { - return url.clone(); + Ok(url) + } else { + Ok(Url::from_file_path(&path) + .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?) } - - let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0]; - let url = Url::from_str(&joined).expect("This came from a valid `Url`"); - url } #[test] fn test_lowercase_drive_letter_with_drive() { - let url = Url::from_file_path("C:\\Test").unwrap(); - let url = lowercase_drive_letter(&url); + let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap(); assert_eq!(url.to_string(), "file:///c:/Test"); } #[test] fn test_drive_without_colon_passthrough() { - let url = Url::from_file_path(r#"\\localhost\C$\my_dir"#).expect("Should work"); - let url = lowercase_drive_letter(&url); + let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap(); - assert_eq!(url.to_string(), "file:///C$/my_dir"); + assert_eq!(url.to_string(), "file://localhost/C$/my_dir"); } -- cgit v1.2.3