diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-06 15:22:00 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-06 15:22:00 +0100 |
commit | 1acd9d5540bf755e87173fe16a803cfe8b2bb500 (patch) | |
tree | a5fb9afa541a4e6ab5818530b3fd19d5e461ef9e /crates/ra_lsp_server/src/main_loop.rs | |
parent | 007737a0e7dd2866e02a6398d8ee4aa7d5051d8c (diff) | |
parent | 28df377759ee5625b0dad4c797be306c8d2624e3 (diff) |
Merge #1780
1780: add option to disable notify r=matklad a=matklad
This should help if notify uses 100% of CPU. Put
```
{
"rust-analyzer.useClientWatching": true,
}
```
into `.vscode/settings.json` (or appropriate config of your editor) to use editor's file watching capabilites instead of notify
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop.rs')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 174 |
1 files changed, 118 insertions, 56 deletions
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 80f0216e8..25fa51b8a 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -9,8 +9,9 @@ use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestI | |||
9 | use lsp_types::{ClientCapabilities, NumberOrString}; | 9 | use lsp_types::{ClientCapabilities, NumberOrString}; |
10 | use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; | 10 | use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | use ra_vfs::VfsTask; | 12 | use ra_vfs::{VfsTask, Watch}; |
13 | use relative_path::RelativePathBuf; | 13 | use relative_path::RelativePathBuf; |
14 | use rustc_hash::FxHashSet; | ||
14 | use serde::{de::DeserializeOwned, Serialize}; | 15 | use serde::{de::DeserializeOwned, Serialize}; |
15 | use threadpool::ThreadPool; | 16 | use threadpool::ThreadPool; |
16 | 17 | ||
@@ -55,72 +56,96 @@ pub fn main_loop( | |||
55 | ) -> Result<()> { | 56 | ) -> Result<()> { |
56 | log::info!("server_config: {:#?}", config); | 57 | log::info!("server_config: {:#?}", config); |
57 | 58 | ||
58 | // FIXME: support dynamic workspace loading. | 59 | let mut loop_state = LoopState::default(); |
59 | let workspaces = { | 60 | let mut world_state = { |
60 | let mut loaded_workspaces = Vec::new(); | 61 | // FIXME: support dynamic workspace loading. |
61 | for ws_root in &ws_roots { | 62 | let workspaces = { |
62 | let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( | 63 | let mut loaded_workspaces = Vec::new(); |
63 | ws_root.as_path(), | 64 | for ws_root in &ws_roots { |
64 | config.with_sysroot, | 65 | let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( |
65 | ); | 66 | ws_root.as_path(), |
66 | match workspace { | 67 | config.with_sysroot, |
67 | Ok(workspace) => loaded_workspaces.push(workspace), | 68 | ); |
68 | Err(e) => { | 69 | match workspace { |
69 | log::error!("loading workspace failed: {}", e); | 70 | Ok(workspace) => loaded_workspaces.push(workspace), |
71 | Err(e) => { | ||
72 | log::error!("loading workspace failed: {}", e); | ||
73 | |||
74 | show_message( | ||
75 | req::MessageType::Error, | ||
76 | format!("rust-analyzer failed to load workspace: {}", e), | ||
77 | &connection.sender, | ||
78 | ); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | loaded_workspaces | ||
83 | }; | ||
70 | 84 | ||
85 | let globs = config | ||
86 | .exclude_globs | ||
87 | .iter() | ||
88 | .map(|glob| ra_vfs_glob::Glob::new(glob)) | ||
89 | .collect::<std::result::Result<Vec<_>, _>>()?; | ||
90 | |||
91 | if config.use_client_watching { | ||
92 | let registration_options = req::DidChangeWatchedFilesRegistrationOptions { | ||
93 | watchers: workspaces | ||
94 | .iter() | ||
95 | .flat_map(|ws| ws.to_roots()) | ||
96 | .filter(|root| root.is_member()) | ||
97 | .map(|root| format!("{}/**/*.rs", root.path().display())) | ||
98 | .map(|glob_pattern| req::FileSystemWatcher { glob_pattern, kind: None }) | ||
99 | .collect(), | ||
100 | }; | ||
101 | let registration = req::Registration { | ||
102 | id: "file-watcher".to_string(), | ||
103 | method: "workspace/didChangeWatchedFiles".to_string(), | ||
104 | register_options: Some(serde_json::to_value(registration_options).unwrap()), | ||
105 | }; | ||
106 | let params = req::RegistrationParams { registrations: vec![registration] }; | ||
107 | let request = | ||
108 | request_new::<req::RegisterCapability>(loop_state.next_request_id(), params); | ||
109 | connection.sender.send(request.into()).unwrap(); | ||
110 | } | ||
111 | |||
112 | let feature_flags = { | ||
113 | let mut ff = FeatureFlags::default(); | ||
114 | for (flag, value) in config.feature_flags { | ||
115 | if let Err(_) = ff.set(flag.as_str(), value) { | ||
116 | log::error!("unknown feature flag: {:?}", flag); | ||
71 | show_message( | 117 | show_message( |
72 | req::MessageType::Error, | 118 | req::MessageType::Error, |
73 | format!("rust-analyzer failed to load workspace: {}", e), | 119 | format!("unknown feature flag: {:?}", flag), |
74 | &connection.sender, | 120 | &connection.sender, |
75 | ); | 121 | ); |
76 | } | 122 | } |
77 | } | 123 | } |
78 | } | 124 | ff |
79 | loaded_workspaces | 125 | }; |
80 | }; | 126 | log::info!("feature_flags: {:#?}", feature_flags); |
81 | 127 | ||
82 | let globs = config | 128 | WorldState::new( |
83 | .exclude_globs | 129 | ws_roots, |
84 | .iter() | 130 | workspaces, |
85 | .map(|glob| ra_vfs_glob::Glob::new(glob)) | 131 | config.lru_capacity, |
86 | .collect::<std::result::Result<Vec<_>, _>>()?; | 132 | &globs, |
87 | 133 | Watch(!config.use_client_watching), | |
88 | let feature_flags = { | 134 | Options { |
89 | let mut ff = FeatureFlags::default(); | 135 | publish_decorations: config.publish_decorations, |
90 | for (flag, value) in config.feature_flags { | 136 | supports_location_link: client_caps |
91 | if let Err(_) = ff.set(flag.as_str(), value) { | 137 | .text_document |
92 | log::error!("unknown feature flag: {:?}", flag); | 138 | .and_then(|it| it.definition) |
93 | show_message( | 139 | .and_then(|it| it.link_support) |
94 | req::MessageType::Error, | 140 | .unwrap_or(false), |
95 | format!("unknown feature flag: {:?}", flag), | 141 | }, |
96 | &connection.sender, | 142 | feature_flags, |
97 | ); | 143 | ) |
98 | } | ||
99 | } | ||
100 | ff | ||
101 | }; | 144 | }; |
102 | log::info!("feature_flags: {:#?}", feature_flags); | ||
103 | |||
104 | let mut world_state = WorldState::new( | ||
105 | ws_roots, | ||
106 | workspaces, | ||
107 | config.lru_capacity, | ||
108 | &globs, | ||
109 | Options { | ||
110 | publish_decorations: config.publish_decorations, | ||
111 | supports_location_link: client_caps | ||
112 | .text_document | ||
113 | .and_then(|it| it.definition) | ||
114 | .and_then(|it| it.link_support) | ||
115 | .unwrap_or(false), | ||
116 | }, | ||
117 | feature_flags, | ||
118 | ); | ||
119 | 145 | ||
120 | let pool = ThreadPool::new(THREADPOOL_SIZE); | 146 | let pool = ThreadPool::new(THREADPOOL_SIZE); |
121 | let (task_sender, task_receiver) = unbounded::<Task>(); | 147 | let (task_sender, task_receiver) = unbounded::<Task>(); |
122 | let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>(); | 148 | let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>(); |
123 | let mut loop_state = LoopState::default(); | ||
124 | 149 | ||
125 | log::info!("server initialized, serving requests"); | 150 | log::info!("server initialized, serving requests"); |
126 | { | 151 | { |
@@ -227,6 +252,8 @@ impl fmt::Debug for Event { | |||
227 | 252 | ||
228 | #[derive(Debug, Default)] | 253 | #[derive(Debug, Default)] |
229 | struct LoopState { | 254 | struct LoopState { |
255 | next_request_id: u64, | ||
256 | pending_responses: FxHashSet<RequestId>, | ||
230 | pending_requests: PendingRequests, | 257 | pending_requests: PendingRequests, |
231 | subscriptions: Subscriptions, | 258 | subscriptions: Subscriptions, |
232 | // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same | 259 | // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same |
@@ -236,6 +263,16 @@ struct LoopState { | |||
236 | workspace_loaded: bool, | 263 | workspace_loaded: bool, |
237 | } | 264 | } |
238 | 265 | ||
266 | impl LoopState { | ||
267 | fn next_request_id(&mut self) -> RequestId { | ||
268 | self.next_request_id += 1; | ||
269 | let res: RequestId = self.next_request_id.into(); | ||
270 | let inserted = self.pending_responses.insert(res.clone()); | ||
271 | assert!(inserted); | ||
272 | res | ||
273 | } | ||
274 | } | ||
275 | |||
239 | fn loop_turn( | 276 | fn loop_turn( |
240 | pool: &ThreadPool, | 277 | pool: &ThreadPool, |
241 | task_sender: &Sender<Task>, | 278 | task_sender: &Sender<Task>, |
@@ -290,7 +327,12 @@ fn loop_turn( | |||
290 | )?; | 327 | )?; |
291 | state_changed = true; | 328 | state_changed = true; |
292 | } | 329 | } |
293 | Message::Response(resp) => log::error!("unexpected response: {:?}", resp), | 330 | Message::Response(resp) => { |
331 | let removed = loop_state.pending_responses.remove(&resp.id); | ||
332 | if !removed { | ||
333 | log::error!("unexpected response: {:?}", resp) | ||
334 | } | ||
335 | } | ||
294 | }, | 336 | }, |
295 | }; | 337 | }; |
296 | 338 | ||
@@ -479,6 +521,18 @@ fn on_notification( | |||
479 | } | 521 | } |
480 | Err(not) => not, | 522 | Err(not) => not, |
481 | }; | 523 | }; |
524 | let not = match notification_cast::<req::DidChangeWatchedFiles>(not) { | ||
525 | Ok(params) => { | ||
526 | let mut vfs = state.vfs.write(); | ||
527 | for change in params.changes { | ||
528 | let uri = change.uri; | ||
529 | let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; | ||
530 | vfs.notify_changed(path) | ||
531 | } | ||
532 | return Ok(()); | ||
533 | } | ||
534 | Err(not) => not, | ||
535 | }; | ||
482 | log::error!("unhandled notification: {:?}", not); | 536 | log::error!("unhandled notification: {:?}", not); |
483 | Ok(()) | 537 | Ok(()) |
484 | } | 538 | } |
@@ -682,3 +736,11 @@ where | |||
682 | { | 736 | { |
683 | Notification::new(N::METHOD.to_string(), params) | 737 | Notification::new(N::METHOD.to_string(), params) |
684 | } | 738 | } |
739 | |||
740 | fn request_new<R>(id: RequestId, params: R::Params) -> Request | ||
741 | where | ||
742 | R: lsp_types::request::Request, | ||
743 | R::Params: Serialize, | ||
744 | { | ||
745 | Request::new(id, R::METHOD.to_string(), params) | ||
746 | } | ||