diff options
Diffstat (limited to 'crates/ra_lsp_server/src/world.rs')
-rw-r--r-- | crates/ra_lsp_server/src/world.rs | 72 |
1 files changed, 12 insertions, 60 deletions
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index 79431e7e6..121ddfd1f 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -12,6 +12,9 @@ use crossbeam_channel::{unbounded, Receiver}; | |||
12 | use lsp_server::ErrorCode; | 12 | use lsp_server::ErrorCode; |
13 | use lsp_types::Url; | 13 | use lsp_types::Url; |
14 | use parking_lot::RwLock; | 14 | use parking_lot::RwLock; |
15 | use ra_cargo_watch::{ | ||
16 | url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher, CheckWatcherSharedState, | ||
17 | }; | ||
15 | use ra_ide::{ | 18 | use ra_ide::{ |
16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, | 19 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, |
17 | SourceRootId, | 20 | SourceRootId, |
@@ -20,13 +23,11 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; | |||
20 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; | 23 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; |
21 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; | 24 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; |
22 | use relative_path::RelativePathBuf; | 25 | use relative_path::RelativePathBuf; |
23 | use std::path::{Component, Prefix}; | ||
24 | 26 | ||
25 | use crate::{ | 27 | use crate::{ |
26 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | 28 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, |
27 | LspError, Result, | 29 | LspError, Result, |
28 | }; | 30 | }; |
29 | use std::str::FromStr; | ||
30 | 31 | ||
31 | #[derive(Debug, Clone)] | 32 | #[derive(Debug, Clone)] |
32 | pub struct Options { | 33 | pub struct Options { |
@@ -34,6 +35,7 @@ pub struct Options { | |||
34 | pub supports_location_link: bool, | 35 | pub supports_location_link: bool, |
35 | pub line_folding_only: bool, | 36 | pub line_folding_only: bool, |
36 | pub max_inlay_hint_length: Option<usize>, | 37 | pub max_inlay_hint_length: Option<usize>, |
38 | pub cargo_watch: CheckOptions, | ||
37 | } | 39 | } |
38 | 40 | ||
39 | /// `WorldState` is the primary mutable state of the language server | 41 | /// `WorldState` is the primary mutable state of the language server |
@@ -52,6 +54,7 @@ pub struct WorldState { | |||
52 | pub vfs: Arc<RwLock<Vfs>>, | 54 | pub vfs: Arc<RwLock<Vfs>>, |
53 | pub task_receiver: Receiver<VfsTask>, | 55 | pub task_receiver: Receiver<VfsTask>, |
54 | pub latest_requests: Arc<RwLock<LatestRequests>>, | 56 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
57 | pub check_watcher: CheckWatcher, | ||
55 | } | 58 | } |
56 | 59 | ||
57 | /// An immutable snapshot of the world's state at a point in time. | 60 | /// An immutable snapshot of the world's state at a point in time. |
@@ -61,6 +64,7 @@ pub struct WorldSnapshot { | |||
61 | pub analysis: Analysis, | 64 | pub analysis: Analysis, |
62 | pub vfs: Arc<RwLock<Vfs>>, | 65 | pub vfs: Arc<RwLock<Vfs>>, |
63 | pub latest_requests: Arc<RwLock<LatestRequests>>, | 66 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
67 | pub check_watcher: Arc<RwLock<CheckWatcherSharedState>>, | ||
64 | } | 68 | } |
65 | 69 | ||
66 | impl WorldState { | 70 | impl WorldState { |
@@ -127,6 +131,10 @@ impl WorldState { | |||
127 | } | 131 | } |
128 | change.set_crate_graph(crate_graph); | 132 | change.set_crate_graph(crate_graph); |
129 | 133 | ||
134 | // FIXME: Figure out the multi-workspace situation | ||
135 | let check_watcher = | ||
136 | CheckWatcher::new(&options.cargo_watch, folder_roots.first().cloned().unwrap()); | ||
137 | |||
130 | let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); | 138 | let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); |
131 | analysis_host.apply_change(change); | 139 | analysis_host.apply_change(change); |
132 | WorldState { | 140 | WorldState { |
@@ -138,6 +146,7 @@ impl WorldState { | |||
138 | vfs: Arc::new(RwLock::new(vfs)), | 146 | vfs: Arc::new(RwLock::new(vfs)), |
139 | task_receiver, | 147 | task_receiver, |
140 | latest_requests: Default::default(), | 148 | latest_requests: Default::default(), |
149 | check_watcher, | ||
141 | } | 150 | } |
142 | } | 151 | } |
143 | 152 | ||
@@ -199,6 +208,7 @@ impl WorldState { | |||
199 | analysis: self.analysis_host.analysis(), | 208 | analysis: self.analysis_host.analysis(), |
200 | vfs: Arc::clone(&self.vfs), | 209 | vfs: Arc::clone(&self.vfs), |
201 | latest_requests: Arc::clone(&self.latest_requests), | 210 | latest_requests: Arc::clone(&self.latest_requests), |
211 | check_watcher: self.check_watcher.shared.clone(), | ||
202 | } | 212 | } |
203 | } | 213 | } |
204 | 214 | ||
@@ -284,61 +294,3 @@ impl WorldSnapshot { | |||
284 | self.analysis.feature_flags() | 294 | self.analysis.feature_flags() |
285 | } | 295 | } |
286 | } | 296 | } |
287 | |||
288 | /// Returns a `Url` object from a given path, will lowercase drive letters if present. | ||
289 | /// This will only happen when processing windows paths. | ||
290 | /// | ||
291 | /// When processing non-windows path, this is essentially the same as `Url::from_file_path`. | ||
292 | fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> { | ||
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)] | ||
329 | mod 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 | } | ||