diff options
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 80 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 95 |
2 files changed, 79 insertions, 96 deletions
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index be5a3f8a7..ca4a248f1 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -7,16 +7,16 @@ use std::{convert::TryFrom, sync::Arc}; | |||
7 | 7 | ||
8 | use crossbeam_channel::{unbounded, Receiver, Sender}; | 8 | use crossbeam_channel::{unbounded, Receiver, Sender}; |
9 | use flycheck::{FlycheckConfig, FlycheckHandle}; | 9 | use flycheck::{FlycheckConfig, FlycheckHandle}; |
10 | use lsp_types::Url; | 10 | use lsp_types::{request::Request, Url}; |
11 | use parking_lot::RwLock; | 11 | use parking_lot::RwLock; |
12 | use ra_db::{CrateId, SourceRoot, VfsPath}; | 12 | use ra_db::{CrateId, SourceRoot, VfsPath}; |
13 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId}; | 13 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId}; |
14 | use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; | 14 | use ra_project_model::{CargoWorkspace, PackageRoot, ProcMacroClient, ProjectWorkspace, Target}; |
15 | use stdx::format_to; | 15 | use stdx::format_to; |
16 | use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf}; | 16 | use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | config::{Config, FilesWatcher}, | 19 | config::{Config, FilesWatcher, LinkedProject}, |
20 | diagnostics::{CheckFixes, DiagnosticCollection}, | 20 | diagnostics::{CheckFixes, DiagnosticCollection}, |
21 | from_proto, | 21 | from_proto, |
22 | line_endings::LineEndings, | 22 | line_endings::LineEndings, |
@@ -98,10 +98,8 @@ pub(crate) struct GlobalStateSnapshot { | |||
98 | impl GlobalState { | 98 | impl GlobalState { |
99 | pub(crate) fn new( | 99 | pub(crate) fn new( |
100 | sender: Sender<lsp_server::Message>, | 100 | sender: Sender<lsp_server::Message>, |
101 | workspaces: Vec<ProjectWorkspace>, | ||
102 | lru_capacity: Option<usize>, | 101 | lru_capacity: Option<usize>, |
103 | config: Config, | 102 | config: Config, |
104 | req_queue: ReqQueue, | ||
105 | ) -> GlobalState { | 103 | ) -> GlobalState { |
106 | let (task_sender, task_receiver) = unbounded::<vfs::loader::Message>(); | 104 | let (task_sender, task_receiver) = unbounded::<vfs::loader::Message>(); |
107 | 105 | ||
@@ -117,7 +115,7 @@ impl GlobalState { | |||
117 | (TaskPool::new(sender), receiver) | 115 | (TaskPool::new(sender), receiver) |
118 | }; | 116 | }; |
119 | 117 | ||
120 | let mut res = GlobalState { | 118 | GlobalState { |
121 | sender, | 119 | sender, |
122 | config, | 120 | config, |
123 | task_pool, | 121 | task_pool, |
@@ -129,17 +127,75 @@ impl GlobalState { | |||
129 | mem_docs: FxHashSet::default(), | 127 | mem_docs: FxHashSet::default(), |
130 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | 128 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), |
131 | status: Status::default(), | 129 | status: Status::default(), |
132 | req_queue, | 130 | req_queue: ReqQueue::default(), |
133 | latest_requests: Default::default(), | 131 | latest_requests: Default::default(), |
134 | source_root_config: SourceRootConfig::default(), | 132 | source_root_config: SourceRootConfig::default(), |
135 | proc_macro_client: ProcMacroClient::dummy(), | 133 | proc_macro_client: ProcMacroClient::dummy(), |
136 | workspaces: Arc::new(Vec::new()), | 134 | workspaces: Arc::new(Vec::new()), |
137 | }; | 135 | } |
138 | res.reload(workspaces); | ||
139 | res | ||
140 | } | 136 | } |
141 | 137 | ||
142 | pub(crate) fn reload(&mut self, workspaces: Vec<ProjectWorkspace>) { | 138 | pub(crate) fn reload(&mut self) { |
139 | let workspaces = { | ||
140 | if self.config.linked_projects.is_empty() | ||
141 | && self.config.notifications.cargo_toml_not_found | ||
142 | { | ||
143 | self.show_message( | ||
144 | lsp_types::MessageType::Error, | ||
145 | "rust-analyzer failed to discover workspace".to_string(), | ||
146 | ); | ||
147 | }; | ||
148 | |||
149 | self.config | ||
150 | .linked_projects | ||
151 | .iter() | ||
152 | .filter_map(|project| match project { | ||
153 | LinkedProject::ProjectManifest(manifest) => { | ||
154 | ra_project_model::ProjectWorkspace::load( | ||
155 | manifest.clone(), | ||
156 | &self.config.cargo, | ||
157 | self.config.with_sysroot, | ||
158 | ) | ||
159 | .map_err(|err| { | ||
160 | log::error!("failed to load workspace: {:#}", err); | ||
161 | self.show_message( | ||
162 | lsp_types::MessageType::Error, | ||
163 | format!("rust-analyzer failed to load workspace: {:#}", err), | ||
164 | ); | ||
165 | }) | ||
166 | .ok() | ||
167 | } | ||
168 | LinkedProject::InlineJsonProject(it) => { | ||
169 | Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() }) | ||
170 | } | ||
171 | }) | ||
172 | .collect::<Vec<_>>() | ||
173 | }; | ||
174 | |||
175 | if let FilesWatcher::Client = self.config.files.watcher { | ||
176 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { | ||
177 | watchers: workspaces | ||
178 | .iter() | ||
179 | .flat_map(ProjectWorkspace::to_roots) | ||
180 | .filter(PackageRoot::is_member) | ||
181 | .map(|root| format!("{}/**/*.rs", root.path().display())) | ||
182 | .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) | ||
183 | .collect(), | ||
184 | }; | ||
185 | let registration = lsp_types::Registration { | ||
186 | id: "file-watcher".to_string(), | ||
187 | method: "workspace/didChangeWatchedFiles".to_string(), | ||
188 | register_options: Some(serde_json::to_value(registration_options).unwrap()), | ||
189 | }; | ||
190 | let params = lsp_types::RegistrationParams { registrations: vec![registration] }; | ||
191 | let request = self.req_queue.outgoing.register( | ||
192 | lsp_types::request::RegisterCapability::METHOD.to_string(), | ||
193 | params, | ||
194 | |_, _| (), | ||
195 | ); | ||
196 | self.send(request.into()); | ||
197 | } | ||
198 | |||
143 | let mut change = AnalysisChange::new(); | 199 | let mut change = AnalysisChange::new(); |
144 | 200 | ||
145 | let project_folders = ProjectFolders::new(&workspaces); | 201 | let project_folders = ProjectFolders::new(&workspaces); |
@@ -275,7 +331,7 @@ impl GlobalState { | |||
275 | self.send(response.into()); | 331 | self.send(response.into()); |
276 | } | 332 | } |
277 | } | 333 | } |
278 | pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) { | 334 | pub(crate) fn show_message(&self, typ: lsp_types::MessageType, message: String) { |
279 | show_message(typ, message, &self.sender) | 335 | show_message(typ, message, &self.sender) |
280 | } | 336 | } |
281 | } | 337 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 1bd9d6389..6ac50745a 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -11,17 +11,14 @@ use lsp_types::{notification::Notification as _, request::Request as _}; | |||
11 | use ra_db::VfsPath; | 11 | use ra_db::VfsPath; |
12 | use ra_ide::{Canceled, FileId}; | 12 | use ra_ide::{Canceled, FileId}; |
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
14 | use ra_project_model::{PackageRoot, ProjectWorkspace}; | ||
15 | 14 | ||
16 | use crate::{ | 15 | use crate::{ |
17 | config::{Config, FilesWatcher, LinkedProject}, | 16 | config::Config, |
18 | dispatch::{NotificationDispatcher, RequestDispatcher}, | 17 | dispatch::{NotificationDispatcher, RequestDispatcher}, |
19 | from_proto, | 18 | from_proto, |
20 | global_state::{file_id_to_url, GlobalState, Status}, | 19 | global_state::{file_id_to_url, GlobalState, Status}, |
21 | handlers, lsp_ext, | 20 | handlers, lsp_ext, |
22 | lsp_utils::{ | 21 | lsp_utils::{apply_document_changes, is_canceled, notification_is, notification_new}, |
23 | apply_document_changes, is_canceled, notification_is, notification_new, show_message, | ||
24 | }, | ||
25 | Result, | 22 | Result, |
26 | }; | 23 | }; |
27 | 24 | ||
@@ -47,81 +44,8 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> { | |||
47 | SetThreadPriority(thread, thread_priority_above_normal); | 44 | SetThreadPriority(thread, thread_priority_above_normal); |
48 | } | 45 | } |
49 | 46 | ||
50 | let global_state = { | 47 | GlobalState::new(connection.sender.clone(), config.lru_capacity, config) |
51 | let workspaces = { | 48 | .run(connection.receiver) |
52 | if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { | ||
53 | show_message( | ||
54 | lsp_types::MessageType::Error, | ||
55 | "rust-analyzer failed to discover workspace".to_string(), | ||
56 | &connection.sender, | ||
57 | ); | ||
58 | }; | ||
59 | |||
60 | config | ||
61 | .linked_projects | ||
62 | .iter() | ||
63 | .filter_map(|project| match project { | ||
64 | LinkedProject::ProjectManifest(manifest) => { | ||
65 | ra_project_model::ProjectWorkspace::load( | ||
66 | manifest.clone(), | ||
67 | &config.cargo, | ||
68 | config.with_sysroot, | ||
69 | ) | ||
70 | .map_err(|err| { | ||
71 | log::error!("failed to load workspace: {:#}", err); | ||
72 | show_message( | ||
73 | lsp_types::MessageType::Error, | ||
74 | format!("rust-analyzer failed to load workspace: {:#}", err), | ||
75 | &connection.sender, | ||
76 | ); | ||
77 | }) | ||
78 | .ok() | ||
79 | } | ||
80 | LinkedProject::InlineJsonProject(it) => { | ||
81 | Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() }) | ||
82 | } | ||
83 | }) | ||
84 | .collect::<Vec<_>>() | ||
85 | }; | ||
86 | |||
87 | let mut req_queue = ReqQueue::default(); | ||
88 | |||
89 | if let FilesWatcher::Client = config.files.watcher { | ||
90 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { | ||
91 | watchers: workspaces | ||
92 | .iter() | ||
93 | .flat_map(ProjectWorkspace::to_roots) | ||
94 | .filter(PackageRoot::is_member) | ||
95 | .map(|root| format!("{}/**/*.rs", root.path().display())) | ||
96 | .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) | ||
97 | .collect(), | ||
98 | }; | ||
99 | let registration = lsp_types::Registration { | ||
100 | id: "file-watcher".to_string(), | ||
101 | method: "workspace/didChangeWatchedFiles".to_string(), | ||
102 | register_options: Some(serde_json::to_value(registration_options).unwrap()), | ||
103 | }; | ||
104 | let params = lsp_types::RegistrationParams { registrations: vec![registration] }; | ||
105 | let request = req_queue.outgoing.register( | ||
106 | lsp_types::request::RegisterCapability::METHOD.to_string(), | ||
107 | params, | ||
108 | DO_NOTHING, | ||
109 | ); | ||
110 | connection.sender.send(request.into()).unwrap(); | ||
111 | } | ||
112 | |||
113 | GlobalState::new( | ||
114 | connection.sender.clone(), | ||
115 | workspaces, | ||
116 | config.lru_capacity, | ||
117 | config, | ||
118 | req_queue, | ||
119 | ) | ||
120 | }; | ||
121 | |||
122 | log::info!("server initialized, serving requests"); | ||
123 | global_state.run(connection.receiver)?; | ||
124 | Ok(()) | ||
125 | } | 49 | } |
126 | 50 | ||
127 | enum Event { | 51 | enum Event { |
@@ -188,23 +112,26 @@ impl GlobalState { | |||
188 | } | 112 | } |
189 | 113 | ||
190 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { | 114 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { |
115 | self.reload(); | ||
116 | |||
191 | while let Some(event) = self.next_event(&inbox) { | 117 | while let Some(event) = self.next_event(&inbox) { |
192 | if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { | 118 | if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { |
193 | if not.method == lsp_types::notification::Exit::METHOD { | 119 | if not.method == lsp_types::notification::Exit::METHOD { |
194 | return Ok(()); | 120 | return Ok(()); |
195 | } | 121 | } |
196 | } | 122 | } |
197 | self.loop_turn(event)? | 123 | self.handle_event(event)? |
198 | } | 124 | } |
125 | |||
199 | Err("client exited without proper shutdown sequence")? | 126 | Err("client exited without proper shutdown sequence")? |
200 | } | 127 | } |
201 | 128 | ||
202 | fn loop_turn(&mut self, event: Event) -> Result<()> { | 129 | fn handle_event(&mut self, event: Event) -> Result<()> { |
203 | let loop_start = Instant::now(); | 130 | let loop_start = Instant::now(); |
204 | // NOTE: don't count blocking select! call as a loop-turn time | 131 | // NOTE: don't count blocking select! call as a loop-turn time |
205 | let _p = profile("main_loop_inner/loop-turn"); | 132 | let _p = profile("GlobalState::handle_event"); |
206 | 133 | ||
207 | log::info!("loop turn = {:?}", event); | 134 | log::info!("handle_event({:?})", event); |
208 | let queue_count = self.task_pool.0.len(); | 135 | let queue_count = self.task_pool.0.len(); |
209 | if queue_count > 0 { | 136 | if queue_count > 0 { |
210 | log::info!("queued count = {}", queue_count); | 137 | log::info!("queued count = {}", queue_count); |