aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-25 22:26:21 +0100
committerAleksey Kladov <[email protected]>2020-06-25 23:27:57 +0100
commit3d0f78213879be78064d70a54411e40a6392a224 (patch)
tree19130beea8e22b8f5e6e19eb7705d6c97e615384 /crates
parent73d73077febba921918b5611574bf514eae63006 (diff)
Prep dynamic workspace loading
Diffstat (limited to 'crates')
-rw-r--r--crates/rust-analyzer/src/global_state.rs80
-rw-r--r--crates/rust-analyzer/src/main_loop.rs95
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
8use crossbeam_channel::{unbounded, Receiver, Sender}; 8use crossbeam_channel::{unbounded, Receiver, Sender};
9use flycheck::{FlycheckConfig, FlycheckHandle}; 9use flycheck::{FlycheckConfig, FlycheckHandle};
10use lsp_types::Url; 10use lsp_types::{request::Request, Url};
11use parking_lot::RwLock; 11use parking_lot::RwLock;
12use ra_db::{CrateId, SourceRoot, VfsPath}; 12use ra_db::{CrateId, SourceRoot, VfsPath};
13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId}; 13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId};
14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use ra_project_model::{CargoWorkspace, PackageRoot, ProcMacroClient, ProjectWorkspace, Target};
15use stdx::format_to; 15use stdx::format_to;
16use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf}; 16use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf};
17 17
18use crate::{ 18use 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 {
98impl GlobalState { 98impl 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 _};
11use ra_db::VfsPath; 11use ra_db::VfsPath;
12use ra_ide::{Canceled, FileId}; 12use ra_ide::{Canceled, FileId};
13use ra_prof::profile; 13use ra_prof::profile;
14use ra_project_model::{PackageRoot, ProjectWorkspace};
15 14
16use crate::{ 15use 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
127enum Event { 51enum 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);