aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-29 17:53:13 +0000
committerGitHub <[email protected]>2019-12-29 17:53:13 +0000
commitfc77921accbcdf410ea3db6363de9fa3d833eba1 (patch)
tree321895dc7b4303a45f449b120328db0482dfef47
parentb30de4ed49be362ed8fd71ac367c90554441b079 (diff)
parent0d69d23d2f9fc23f53960eca60cdaea1a7e2281f (diff)
Merge #2680
2680: Fix cargo-watcher file urls on windows r=matklad a=kiljacken Fixes #2676 Co-authored-by: Emil Lauridsen <[email protected]>
-rw-r--r--crates/ra_cargo_watch/src/conv.rs68
-rw-r--r--crates/ra_cargo_watch/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/src/world.rs64
3 files changed, 71 insertions, 63 deletions
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index 3bd4bf7a5..dedb0751e 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_cargo_watch/src/conv.rs
@@ -8,7 +8,11 @@ use lsp_types::{
8 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location, 8 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
9 NumberOrString, Position, Range, Url, 9 NumberOrString, Position, Range, Url,
10}; 10};
11use std::{fmt::Write, path::PathBuf}; 11use std::{
12 fmt::Write,
13 path::{Component, Path, PathBuf, Prefix},
14 str::FromStr,
15};
12 16
13#[cfg(test)] 17#[cfg(test)]
14mod test; 18mod test;
@@ -57,7 +61,7 @@ fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &PathBuf) -> Loca
57 61
58 let mut file_name = workspace_root.clone(); 62 let mut file_name = workspace_root.clone();
59 file_name.push(&span.file_name); 63 file_name.push(&span.file_name);
60 let uri = Url::from_file_path(file_name).unwrap(); 64 let uri = url_from_path_with_drive_lowercasing(file_name).unwrap();
61 65
62 let range = Range::new( 66 let range = Range::new(
63 Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1), 67 Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1),
@@ -278,3 +282,63 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
278 282
279 Some(MappedRustDiagnostic { location, diagnostic, suggested_fixes }) 283 Some(MappedRustDiagnostic { location, diagnostic, suggested_fixes })
280} 284}
285
286/// Returns a `Url` object from a given path, will lowercase drive letters if present.
287/// This will only happen when processing windows paths.
288///
289/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
290pub fn url_from_path_with_drive_lowercasing(
291 path: impl AsRef<Path>,
292) -> Result<Url, Box<dyn std::error::Error + Send + Sync>> {
293 let component_has_windows_drive = path.as_ref().components().any(|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
303 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
304 if component_has_windows_drive {
305 let url_original = Url::from_file_path(&path)
306 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
307
308 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
309
310 // There is a drive partition, but we never found a colon.
311 // This should not happen, but in this case we just pass it through.
312 if drive_partition.len() == 1 {
313 return Ok(url_original);
314 }
315
316 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
317 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
318
319 Ok(url)
320 } else {
321 Ok(Url::from_file_path(&path)
322 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
323 }
324}
325
326// `Url` is not able to parse windows paths on unix machines.
327#[cfg(target_os = "windows")]
328#[cfg(test)]
329mod path_conversion_windows_tests {
330 use super::url_from_path_with_drive_lowercasing;
331 #[test]
332 fn test_lowercase_drive_letter_with_drive() {
333 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
334
335 assert_eq!(url.to_string(), "file:///c:/Test");
336 }
337
338 #[test]
339 fn test_drive_without_colon_passthrough() {
340 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
341
342 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
343 }
344}
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index e5c22e599..9bc0fd405 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -21,6 +21,8 @@ mod conv;
21 21
22use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic, SuggestedFix}; 22use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic, SuggestedFix};
23 23
24pub use crate::conv::url_from_path_with_drive_lowercasing;
25
24#[derive(Clone, Debug)] 26#[derive(Clone, Debug)]
25pub struct CheckOptions { 27pub struct CheckOptions {
26 pub enable: bool, 28 pub enable: bool,
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 4b3959e38..121ddfd1f 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -12,7 +12,9 @@ use crossbeam_channel::{unbounded, Receiver};
12use lsp_server::ErrorCode; 12use lsp_server::ErrorCode;
13use lsp_types::Url; 13use lsp_types::Url;
14use parking_lot::RwLock; 14use parking_lot::RwLock;
15use ra_cargo_watch::{CheckOptions, CheckWatcher, CheckWatcherSharedState}; 15use ra_cargo_watch::{
16 url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher, CheckWatcherSharedState,
17};
16use ra_ide::{ 18use ra_ide::{
17 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, 19 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
18 SourceRootId, 20 SourceRootId,
@@ -21,13 +23,11 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
21use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 23use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
22use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 24use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
23use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
24use std::path::{Component, Prefix};
25 26
26use crate::{ 27use crate::{
27 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 28 main_loop::pending_requests::{CompletedRequest, LatestRequests},
28 LspError, Result, 29 LspError, Result,
29}; 30};
30use std::str::FromStr;
31 31
32#[derive(Debug, Clone)] 32#[derive(Debug, Clone)]
33pub struct Options { 33pub struct Options {
@@ -294,61 +294,3 @@ impl WorldSnapshot {
294 self.analysis.feature_flags() 294 self.analysis.feature_flags()
295 } 295 }
296} 296}
297
298/// Returns a `Url` object from a given path, will lowercase drive letters if present.
299/// This will only happen when processing windows paths.
300///
301/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
302fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
303 let component_has_windows_drive = path.as_ref().components().any(|comp| {
304 if let Component::Prefix(c) = comp {
305 match c.kind() {
306 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
307 _ => return false,
308 }
309 }
310 false
311 });
312
313 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
314 if component_has_windows_drive {
315 let url_original = Url::from_file_path(&path)
316 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
317
318 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
319
320 // There is a drive partition, but we never found a colon.
321 // This should not happen, but in this case we just pass it through.
322 if drive_partition.len() == 1 {
323 return Ok(url_original);
324 }
325
326 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
327 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
328
329 Ok(url)
330 } else {
331 Ok(Url::from_file_path(&path)
332 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
333 }
334}
335
336// `Url` is not able to parse windows paths on unix machines.
337#[cfg(target_os = "windows")]
338#[cfg(test)]
339mod path_conversion_windows_tests {
340 use super::url_from_path_with_drive_lowercasing;
341 #[test]
342 fn test_lowercase_drive_letter_with_drive() {
343 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
344
345 assert_eq!(url.to_string(), "file:///c:/Test");
346 }
347
348 #[test]
349 fn test_drive_without_colon_passthrough() {
350 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
351
352 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
353 }
354}