aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/main_loop.rs
diff options
context:
space:
mode:
authorMikhail Rakhmanov <[email protected]>2020-06-03 18:26:01 +0100
committerMikhail Rakhmanov <[email protected]>2020-06-03 18:26:01 +0100
commit6a0083a519680e8d16bde5d7c1940c8dd6d4e9d4 (patch)
tree2b377141d722257cfea18e74b955aea1a8f6cc1a /crates/rust-analyzer/src/main_loop.rs
parent1f7de306f547ecb394a34445fd6ac1d6bc8ab439 (diff)
parent794f6da821c5d6e2490b996baffe162e4753262d (diff)
Merge branch 'master' into compute-lazy-assits
# Conflicts: # crates/rust-analyzer/src/main_loop/handlers.rs # crates/rust-analyzer/src/to_proto.rs
Diffstat (limited to 'crates/rust-analyzer/src/main_loop.rs')
-rw-r--r--crates/rust-analyzer/src/main_loop.rs147
1 files changed, 71 insertions, 76 deletions
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ad9dd4c59..e60337b8e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -12,13 +12,11 @@ use std::{
12 fmt, 12 fmt,
13 ops::Range, 13 ops::Range,
14 panic, 14 panic,
15 path::PathBuf,
16 sync::Arc, 15 sync::Arc,
17 time::{Duration, Instant}, 16 time::{Duration, Instant},
18}; 17};
19 18
20use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; 19use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
21use itertools::Itertools;
22use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 20use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
23use lsp_types::{ 21use lsp_types::{
24 DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, 22 DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress,
@@ -36,14 +34,15 @@ use serde::{de::DeserializeOwned, Serialize};
36use threadpool::ThreadPool; 34use threadpool::ThreadPool;
37 35
38use crate::{ 36use crate::{
39 config::{Config, FilesWatcher}, 37 config::{Config, FilesWatcher, LinkedProject},
40 diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, 38 diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask},
41 from_proto, lsp_ext, 39 from_proto,
40 global_state::{GlobalState, GlobalStateSnapshot},
41 lsp_ext,
42 main_loop::{ 42 main_loop::{
43 pending_requests::{PendingRequest, PendingRequests}, 43 pending_requests::{PendingRequest, PendingRequests},
44 subscriptions::Subscriptions, 44 subscriptions::Subscriptions,
45 }, 45 },
46 world::{WorldSnapshot, WorldState},
47 Result, 46 Result,
48}; 47};
49 48
@@ -69,7 +68,7 @@ impl fmt::Display for LspError {
69 68
70impl Error for LspError {} 69impl Error for LspError {}
71 70
72pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) -> Result<()> { 71pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
73 log::info!("initial config: {:#?}", config); 72 log::info!("initial config: {:#?}", config);
74 73
75 // Windows scheduler implements priority boosts: if thread waits for an 74 // Windows scheduler implements priority boosts: if thread waits for an
@@ -92,43 +91,37 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
92 } 91 }
93 92
94 let mut loop_state = LoopState::default(); 93 let mut loop_state = LoopState::default();
95 let mut world_state = { 94 let mut global_state = {
96 let workspaces = { 95 let workspaces = {
97 // FIXME: support dynamic workspace loading. 96 if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found {
98 let project_roots: FxHashSet<_> = ws_roots
99 .iter()
100 .filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok())
101 .flatten()
102 .collect();
103
104 if project_roots.is_empty() && config.notifications.cargo_toml_not_found {
105 show_message( 97 show_message(
106 lsp_types::MessageType::Error, 98 lsp_types::MessageType::Error,
107 format!( 99 "rust-analyzer failed to discover workspace".to_string(),
108 "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}",
109 ws_roots.iter().format_with(", ", |it, f| f(&it.display()))
110 ),
111 &connection.sender, 100 &connection.sender,
112 ); 101 );
113 }; 102 };
114 103
115 project_roots 104 config
116 .into_iter() 105 .linked_projects
117 .filter_map(|root| { 106 .iter()
118 ra_project_model::ProjectWorkspace::load( 107 .filter_map(|project| match project {
119 root, 108 LinkedProject::ProjectManifest(manifest) => {
120 &config.cargo, 109 ra_project_model::ProjectWorkspace::load(
121 config.with_sysroot, 110 manifest.clone(),
122 ) 111 &config.cargo,
123 .map_err(|err| { 112 config.with_sysroot,
124 log::error!("failed to load workspace: {:#}", err); 113 )
125 show_message( 114 .map_err(|err| {
126 lsp_types::MessageType::Error, 115 log::error!("failed to load workspace: {:#}", err);
127 format!("rust-analyzer failed to load workspace: {:#}", err), 116 show_message(
128 &connection.sender, 117 lsp_types::MessageType::Error,
129 ); 118 format!("rust-analyzer failed to load workspace: {:#}", err),
130 }) 119 &connection.sender,
131 .ok() 120 );
121 })
122 .ok()
123 }
124 LinkedProject::JsonProject(it) => Some(it.clone().into()),
132 }) 125 })
133 .collect::<Vec<_>>() 126 .collect::<Vec<_>>()
134 }; 127 };
@@ -163,8 +156,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
163 connection.sender.send(request.into()).unwrap(); 156 connection.sender.send(request.into()).unwrap();
164 } 157 }
165 158
166 WorldState::new( 159 GlobalState::new(
167 ws_roots,
168 workspaces, 160 workspaces,
169 config.lru_capacity, 161 config.lru_capacity,
170 &globs, 162 &globs,
@@ -173,7 +165,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
173 ) 165 )
174 }; 166 };
175 167
176 loop_state.roots_total = world_state.vfs.read().n_roots(); 168 loop_state.roots_total = global_state.vfs.read().n_roots();
177 169
178 let pool = ThreadPool::default(); 170 let pool = ThreadPool::default();
179 let (task_sender, task_receiver) = unbounded::<Task>(); 171 let (task_sender, task_receiver) = unbounded::<Task>();
@@ -191,12 +183,12 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
191 Err(RecvError) => return Err("client exited without shutdown".into()), 183 Err(RecvError) => return Err("client exited without shutdown".into()),
192 }, 184 },
193 recv(task_receiver) -> task => Event::Task(task.unwrap()), 185 recv(task_receiver) -> task => Event::Task(task.unwrap()),
194 recv(world_state.task_receiver) -> task => match task { 186 recv(global_state.task_receiver) -> task => match task {
195 Ok(task) => Event::Vfs(task), 187 Ok(task) => Event::Vfs(task),
196 Err(RecvError) => return Err("vfs died".into()), 188 Err(RecvError) => return Err("vfs died".into()),
197 }, 189 },
198 recv(libdata_receiver) -> data => Event::Lib(data.unwrap()), 190 recv(libdata_receiver) -> data => Event::Lib(data.unwrap()),
199 recv(world_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { 191 recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task {
200 Ok(task) => Event::CheckWatcher(task), 192 Ok(task) => Event::CheckWatcher(task),
201 Err(RecvError) => return Err("check watcher died".into()), 193 Err(RecvError) => return Err("check watcher died".into()),
202 } 194 }
@@ -211,16 +203,16 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
211 &task_sender, 203 &task_sender,
212 &libdata_sender, 204 &libdata_sender,
213 &connection, 205 &connection,
214 &mut world_state, 206 &mut global_state,
215 &mut loop_state, 207 &mut loop_state,
216 event, 208 event,
217 )?; 209 )?;
218 } 210 }
219 } 211 }
220 world_state.analysis_host.request_cancellation(); 212 global_state.analysis_host.request_cancellation();
221 log::info!("waiting for tasks to finish..."); 213 log::info!("waiting for tasks to finish...");
222 task_receiver.into_iter().for_each(|task| { 214 task_receiver.into_iter().for_each(|task| {
223 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) 215 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut global_state)
224 }); 216 });
225 libdata_receiver.into_iter().for_each(drop); 217 libdata_receiver.into_iter().for_each(drop);
226 log::info!("...tasks have finished"); 218 log::info!("...tasks have finished");
@@ -229,7 +221,7 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
229 drop(pool); 221 drop(pool);
230 log::info!("...threadpool has finished"); 222 log::info!("...threadpool has finished");
231 223
232 let vfs = Arc::try_unwrap(world_state.vfs).expect("all snapshots should be dead"); 224 let vfs = Arc::try_unwrap(global_state.vfs).expect("all snapshots should be dead");
233 drop(vfs); 225 drop(vfs);
234 226
235 Ok(()) 227 Ok(())
@@ -320,7 +312,7 @@ fn loop_turn(
320 task_sender: &Sender<Task>, 312 task_sender: &Sender<Task>,
321 libdata_sender: &Sender<LibraryData>, 313 libdata_sender: &Sender<LibraryData>,
322 connection: &Connection, 314 connection: &Connection,
323 world_state: &mut WorldState, 315 global_state: &mut GlobalState,
324 loop_state: &mut LoopState, 316 loop_state: &mut LoopState,
325 event: Event, 317 event: Event,
326) -> Result<()> { 318) -> Result<()> {
@@ -336,22 +328,22 @@ fn loop_turn(
336 328
337 match event { 329 match event {
338 Event::Task(task) => { 330 Event::Task(task) => {
339 on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); 331 on_task(task, &connection.sender, &mut loop_state.pending_requests, global_state);
340 world_state.maybe_collect_garbage(); 332 global_state.maybe_collect_garbage();
341 } 333 }
342 Event::Vfs(task) => { 334 Event::Vfs(task) => {
343 world_state.vfs.write().handle_task(task); 335 global_state.vfs.write().handle_task(task);
344 } 336 }
345 Event::Lib(lib) => { 337 Event::Lib(lib) => {
346 world_state.add_lib(lib); 338 global_state.add_lib(lib);
347 world_state.maybe_collect_garbage(); 339 global_state.maybe_collect_garbage();
348 loop_state.in_flight_libraries -= 1; 340 loop_state.in_flight_libraries -= 1;
349 loop_state.roots_scanned += 1; 341 loop_state.roots_scanned += 1;
350 } 342 }
351 Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, 343 Event::CheckWatcher(task) => on_check_task(task, global_state, task_sender)?,
352 Event::Msg(msg) => match msg { 344 Event::Msg(msg) => match msg {
353 Message::Request(req) => on_request( 345 Message::Request(req) => on_request(
354 world_state, 346 global_state,
355 &mut loop_state.pending_requests, 347 &mut loop_state.pending_requests,
356 pool, 348 pool,
357 task_sender, 349 task_sender,
@@ -360,7 +352,7 @@ fn loop_turn(
360 req, 352 req,
361 )?, 353 )?,
362 Message::Notification(not) => { 354 Message::Notification(not) => {
363 on_notification(&connection.sender, world_state, loop_state, not)?; 355 on_notification(&connection.sender, global_state, loop_state, not)?;
364 } 356 }
365 Message::Response(resp) => { 357 Message::Response(resp) => {
366 let removed = loop_state.pending_responses.remove(&resp.id); 358 let removed = loop_state.pending_responses.remove(&resp.id);
@@ -379,9 +371,9 @@ fn loop_turn(
379 } 371 }
380 (None, Some(configs)) => { 372 (None, Some(configs)) => {
381 if let Some(new_config) = configs.get(0) { 373 if let Some(new_config) = configs.get(0) {
382 let mut config = world_state.config.clone(); 374 let mut config = global_state.config.clone();
383 config.update(&new_config); 375 config.update(&new_config);
384 world_state.update_configuration(config); 376 global_state.update_configuration(config);
385 } 377 }
386 } 378 }
387 (None, None) => { 379 (None, None) => {
@@ -394,7 +386,7 @@ fn loop_turn(
394 }; 386 };
395 387
396 let mut state_changed = false; 388 let mut state_changed = false;
397 if let Some(changes) = world_state.process_changes(&mut loop_state.roots_scanned) { 389 if let Some(changes) = global_state.process_changes(&mut loop_state.roots_scanned) {
398 state_changed = true; 390 state_changed = true;
399 loop_state.pending_libraries.extend(changes); 391 loop_state.pending_libraries.extend(changes);
400 } 392 }
@@ -416,7 +408,7 @@ fn loop_turn(
416 } 408 }
417 409
418 let show_progress = 410 let show_progress =
419 !loop_state.workspace_loaded && world_state.config.client_caps.work_done_progress; 411 !loop_state.workspace_loaded && global_state.config.client_caps.work_done_progress;
420 412
421 if !loop_state.workspace_loaded 413 if !loop_state.workspace_loaded
422 && loop_state.roots_scanned == loop_state.roots_total 414 && loop_state.roots_scanned == loop_state.roots_total
@@ -425,7 +417,7 @@ fn loop_turn(
425 { 417 {
426 state_changed = true; 418 state_changed = true;
427 loop_state.workspace_loaded = true; 419 loop_state.workspace_loaded = true;
428 if let Some(flycheck) = &world_state.flycheck { 420 if let Some(flycheck) = &global_state.flycheck {
429 flycheck.update(); 421 flycheck.update();
430 } 422 }
431 } 423 }
@@ -437,13 +429,13 @@ fn loop_turn(
437 if state_changed && loop_state.workspace_loaded { 429 if state_changed && loop_state.workspace_loaded {
438 update_file_notifications_on_threadpool( 430 update_file_notifications_on_threadpool(
439 pool, 431 pool,
440 world_state.snapshot(), 432 global_state.snapshot(),
441 task_sender.clone(), 433 task_sender.clone(),
442 loop_state.subscriptions.subscriptions(), 434 loop_state.subscriptions.subscriptions(),
443 ); 435 );
444 pool.execute({ 436 pool.execute({
445 let subs = loop_state.subscriptions.subscriptions(); 437 let subs = loop_state.subscriptions.subscriptions();
446 let snap = world_state.snapshot(); 438 let snap = global_state.snapshot();
447 move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ()) 439 move || snap.analysis().prime_caches(subs).unwrap_or_else(|_: Canceled| ())
448 }); 440 });
449 } 441 }
@@ -467,7 +459,7 @@ fn on_task(
467 task: Task, 459 task: Task,
468 msg_sender: &Sender<Message>, 460 msg_sender: &Sender<Message>,
469 pending_requests: &mut PendingRequests, 461 pending_requests: &mut PendingRequests,
470 state: &mut WorldState, 462 state: &mut GlobalState,
471) { 463) {
472 match task { 464 match task {
473 Task::Respond(response) => { 465 Task::Respond(response) => {
@@ -485,7 +477,7 @@ fn on_task(
485} 477}
486 478
487fn on_request( 479fn on_request(
488 world: &mut WorldState, 480 global_state: &mut GlobalState,
489 pending_requests: &mut PendingRequests, 481 pending_requests: &mut PendingRequests,
490 pool: &ThreadPool, 482 pool: &ThreadPool,
491 task_sender: &Sender<Task>, 483 task_sender: &Sender<Task>,
@@ -496,7 +488,7 @@ fn on_request(
496 let mut pool_dispatcher = PoolDispatcher { 488 let mut pool_dispatcher = PoolDispatcher {
497 req: Some(req), 489 req: Some(req),
498 pool, 490 pool,
499 world, 491 global_state,
500 task_sender, 492 task_sender,
501 msg_sender, 493 msg_sender,
502 pending_requests, 494 pending_requests,
@@ -553,7 +545,7 @@ fn on_request(
553 545
554fn on_notification( 546fn on_notification(
555 msg_sender: &Sender<Message>, 547 msg_sender: &Sender<Message>,
556 state: &mut WorldState, 548 state: &mut GlobalState,
557 loop_state: &mut LoopState, 549 loop_state: &mut LoopState,
558 not: Notification, 550 not: Notification,
559) -> Result<()> { 551) -> Result<()> {
@@ -727,7 +719,7 @@ fn apply_document_changes(
727 719
728fn on_check_task( 720fn on_check_task(
729 task: CheckTask, 721 task: CheckTask,
730 world_state: &mut WorldState, 722 global_state: &mut GlobalState,
731 task_sender: &Sender<Task>, 723 task_sender: &Sender<Task>,
732) -> Result<()> { 724) -> Result<()> {
733 match task { 725 match task {
@@ -746,7 +738,7 @@ fn on_check_task(
746 .uri 738 .uri
747 .to_file_path() 739 .to_file_path()
748 .map_err(|()| format!("invalid uri: {}", diag.location.uri))?; 740 .map_err(|()| format!("invalid uri: {}", diag.location.uri))?;
749 let file_id = match world_state.vfs.read().path2file(&path) { 741 let file_id = match global_state.vfs.read().path2file(&path) {
750 Some(file) => FileId(file.0), 742 Some(file) => FileId(file.0),
751 None => { 743 None => {
752 log::error!( 744 log::error!(
@@ -766,7 +758,7 @@ fn on_check_task(
766 } 758 }
767 759
768 CheckTask::Status(status) => { 760 CheckTask::Status(status) => {
769 if world_state.config.client_caps.work_done_progress { 761 if global_state.config.client_caps.work_done_progress {
770 let progress = match status { 762 let progress = match status {
771 Status::Being => { 763 Status::Being => {
772 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { 764 lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin {
@@ -805,7 +797,7 @@ fn on_check_task(
805 Ok(()) 797 Ok(())
806} 798}
807 799
808fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut WorldState) { 800fn on_diagnostic_task(task: DiagnosticTask, msg_sender: &Sender<Message>, state: &mut GlobalState) {
809 let subscriptions = state.diagnostics.handle_task(task); 801 let subscriptions = state.diagnostics.handle_task(task);
810 802
811 for file_id in subscriptions { 803 for file_id in subscriptions {
@@ -880,7 +872,7 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
880struct PoolDispatcher<'a> { 872struct PoolDispatcher<'a> {
881 req: Option<Request>, 873 req: Option<Request>,
882 pool: &'a ThreadPool, 874 pool: &'a ThreadPool,
883 world: &'a mut WorldState, 875 global_state: &'a mut GlobalState,
884 pending_requests: &'a mut PendingRequests, 876 pending_requests: &'a mut PendingRequests,
885 msg_sender: &'a Sender<Message>, 877 msg_sender: &'a Sender<Message>,
886 task_sender: &'a Sender<Task>, 878 task_sender: &'a Sender<Task>,
@@ -891,7 +883,7 @@ impl<'a> PoolDispatcher<'a> {
891 /// Dispatches the request onto the current thread 883 /// Dispatches the request onto the current thread
892 fn on_sync<R>( 884 fn on_sync<R>(
893 &mut self, 885 &mut self,
894 f: fn(&mut WorldState, R::Params) -> Result<R::Result>, 886 f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
895 ) -> Result<&mut Self> 887 ) -> Result<&mut Self>
896 where 888 where
897 R: lsp_types::request::Request + 'static, 889 R: lsp_types::request::Request + 'static,
@@ -904,18 +896,21 @@ impl<'a> PoolDispatcher<'a> {
904 return Ok(self); 896 return Ok(self);
905 } 897 }
906 }; 898 };
907 let world = panic::AssertUnwindSafe(&mut *self.world); 899 let world = panic::AssertUnwindSafe(&mut *self.global_state);
908 let task = panic::catch_unwind(move || { 900 let task = panic::catch_unwind(move || {
909 let result = f(world.0, params); 901 let result = f(world.0, params);
910 result_to_task::<R>(id, result) 902 result_to_task::<R>(id, result)
911 }) 903 })
912 .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; 904 .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?;
913 on_task(task, self.msg_sender, self.pending_requests, self.world); 905 on_task(task, self.msg_sender, self.pending_requests, self.global_state);
914 Ok(self) 906 Ok(self)
915 } 907 }
916 908
917 /// Dispatches the request onto thread pool 909 /// Dispatches the request onto thread pool
918 fn on<R>(&mut self, f: fn(WorldSnapshot, R::Params) -> Result<R::Result>) -> Result<&mut Self> 910 fn on<R>(
911 &mut self,
912 f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
913 ) -> Result<&mut Self>
919 where 914 where
920 R: lsp_types::request::Request + 'static, 915 R: lsp_types::request::Request + 'static,
921 R::Params: DeserializeOwned + Send + 'static, 916 R::Params: DeserializeOwned + Send + 'static,
@@ -929,7 +924,7 @@ impl<'a> PoolDispatcher<'a> {
929 }; 924 };
930 925
931 self.pool.execute({ 926 self.pool.execute({
932 let world = self.world.snapshot(); 927 let world = self.global_state.snapshot();
933 let sender = self.task_sender.clone(); 928 let sender = self.task_sender.clone();
934 move || { 929 move || {
935 let result = f(world, params); 930 let result = f(world, params);
@@ -1013,7 +1008,7 @@ where
1013 1008
1014fn update_file_notifications_on_threadpool( 1009fn update_file_notifications_on_threadpool(
1015 pool: &ThreadPool, 1010 pool: &ThreadPool,
1016 world: WorldSnapshot, 1011 world: GlobalStateSnapshot,
1017 task_sender: Sender<Task>, 1012 task_sender: Sender<Task>,
1018 subscriptions: Vec<FileId>, 1013 subscriptions: Vec<FileId>,
1019) { 1014) {