aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r--crates/ra_lsp_server/src/world.rs68
1 files changed, 66 insertions, 2 deletions
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 927449b45..16cc11e8c 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,8 +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()))?; 239
238 Ok(url) 240 Ok(url)
239 } 241 }
240 242
@@ -279,3 +281,65 @@ impl WorldSnapshot {
279 self.analysis.feature_flags() 281 self.analysis.feature_flags()
280 } 282 }
281} 283}
284
285/// Returns a `Url` object from a given path, will lowercase drive letters if present.
286/// This will only happen when processing windows paths.
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> = url_original.as_str().rsplitn(2, ':').collect();
310
311 // There is a drive partition, but we never found a colon.
312 // This should not happen, but in this case we just pass it through.
313 if drive_partition.len() == 1 {
314 return Ok(url_original);
315 }
316
317 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
318 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
319
320 Ok(url)
321 } else {
322 Ok(Url::from_file_path(&path)
323 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
324 }
325}
326
327// `Url` is not able to parse windows paths on unix machines.
328#[cfg(target_os = "windows")]
329#[cfg(test)]
330mod path_conversion_windows_tests {
331 use super::url_from_path_with_drive_lowercasing;
332 #[test]
333 fn test_lowercase_drive_letter_with_drive() {
334 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
335
336 assert_eq!(url.to_string(), "file:///c:/Test");
337 }
338
339 #[test]
340 fn test_drive_without_colon_passthrough() {
341 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
342
343 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
344 }
345}