aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch/src/conv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cargo_watch/src/conv.rs')
-rw-r--r--crates/ra_cargo_watch/src/conv.rs68
1 files changed, 66 insertions, 2 deletions
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index 172f6b07c..ac0f1d28a 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;
@@ -62,7 +66,7 @@ fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &PathBuf) -> Loca
62fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &PathBuf) -> Location { 66fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &PathBuf) -> Location {
63 let mut file_name = workspace_root.clone(); 67 let mut file_name = workspace_root.clone();
64 file_name.push(&span.file_name); 68 file_name.push(&span.file_name);
65 let uri = Url::from_file_path(file_name).unwrap(); 69 let uri = url_from_path_with_drive_lowercasing(file_name).unwrap();
66 70
67 let range = Range::new( 71 let range = Range::new(
68 Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1), 72 Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1),
@@ -293,3 +297,63 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
293 297
294 Some(MappedRustDiagnostic { location, diagnostic, suggested_fixes }) 298 Some(MappedRustDiagnostic { location, diagnostic, suggested_fixes })
295} 299}
300
301/// Returns a `Url` object from a given path, will lowercase drive letters if present.
302/// This will only happen when processing windows paths.
303///
304/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
305pub fn url_from_path_with_drive_lowercasing(
306 path: impl AsRef<Path>,
307) -> Result<Url, Box<dyn std::error::Error + Send + Sync>> {
308 let component_has_windows_drive = path.as_ref().components().any(|comp| {
309 if let Component::Prefix(c) = comp {
310 match c.kind() {
311 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
312 _ => return false,
313 }
314 }
315 false
316 });
317
318 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
319 if component_has_windows_drive {
320 let url_original = Url::from_file_path(&path)
321 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
322
323 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
324
325 // There is a drive partition, but we never found a colon.
326 // This should not happen, but in this case we just pass it through.
327 if drive_partition.len() == 1 {
328 return Ok(url_original);
329 }
330
331 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
332 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
333
334 Ok(url)
335 } else {
336 Ok(Url::from_file_path(&path)
337 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
338 }
339}
340
341// `Url` is not able to parse windows paths on unix machines.
342#[cfg(target_os = "windows")]
343#[cfg(test)]
344mod path_conversion_windows_tests {
345 use super::url_from_path_with_drive_lowercasing;
346 #[test]
347 fn test_lowercase_drive_letter_with_drive() {
348 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
349
350 assert_eq!(url.to_string(), "file:///c:/Test");
351 }
352
353 #[test]
354 fn test_drive_without_colon_passthrough() {
355 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
356
357 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
358 }
359}