aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/main_loop.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-12-19 12:04:15 +0000
committerAleksey Kladov <[email protected]>2018-12-20 09:15:38 +0000
commita5ef8ad05b7c1f7148c59814b55d641fd75aff75 (patch)
treedf6c46378d81dc7cb3242ff7f57d836353bde5ed /crates/ra_lsp_server/src/main_loop.rs
parent6a755ed83a583d1f70a5fbcff2d4933b52628cfe (diff)
swtich lsp server to vfs
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop.rs')
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs143
1 files changed, 54 insertions, 89 deletions
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 9d3f83b4c..7904545d3 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -1,7 +1,10 @@
1mod handlers; 1mod handlers;
2mod subscriptions; 2mod subscriptions;
3 3
4use std::path::PathBuf; 4use std::{
5 path::PathBuf,
6 sync::Arc,
7};
5 8
6use crossbeam_channel::{unbounded, select, Receiver, Sender}; 9use crossbeam_channel::{unbounded, select, Receiver, Sender};
7use gen_lsp_server::{ 10use gen_lsp_server::{
@@ -9,8 +12,8 @@ use gen_lsp_server::{
9}; 12};
10use languageserver_types::NumberOrString; 13use languageserver_types::NumberOrString;
11use ra_analysis::{Canceled, FileId, LibraryData}; 14use ra_analysis::{Canceled, FileId, LibraryData};
15use ra_vfs::{VfsTask};
12use rayon; 16use rayon;
13use thread_worker::Worker;
14use threadpool::ThreadPool; 17use threadpool::ThreadPool;
15use rustc_hash::FxHashSet; 18use rustc_hash::FxHashSet;
16use serde::{de::DeserializeOwned, Serialize}; 19use serde::{de::DeserializeOwned, Serialize};
@@ -19,10 +22,9 @@ use failure_derive::Fail;
19 22
20use crate::{ 23use crate::{
21 main_loop::subscriptions::Subscriptions, 24 main_loop::subscriptions::Subscriptions,
22 project_model::{workspace_loader, CargoWorkspace}, 25 project_model::{workspace_loader},
23 req, 26 req,
24 server_world::{ServerWorld, ServerWorldState}, 27 server_world::{ServerWorld, ServerWorldState},
25 vfs::{self, FileEvent},
26 Result, 28 Result,
27}; 29};
28 30
@@ -50,32 +52,42 @@ enum Task {
50 52
51pub fn main_loop( 53pub fn main_loop(
52 internal_mode: bool, 54 internal_mode: bool,
53 root: PathBuf, 55 ws_root: PathBuf,
54 publish_decorations: bool, 56 publish_decorations: bool,
55 msg_receiver: &Receiver<RawMessage>, 57 msg_receiver: &Receiver<RawMessage>,
56 msg_sender: &Sender<RawMessage>, 58 msg_sender: &Sender<RawMessage>,
57) -> Result<()> { 59) -> Result<()> {
58 let pool = ThreadPool::new(8); 60 let pool = ThreadPool::new(8);
59 let (task_sender, task_receiver) = unbounded::<Task>(); 61 let (task_sender, task_receiver) = unbounded::<Task>();
60 let (fs_worker, fs_watcher) = vfs::roots_loader();
61 let (ws_worker, ws_watcher) = workspace_loader(); 62 let (ws_worker, ws_watcher) = workspace_loader();
62 63
64 ws_worker.send(ws_root.clone());
65 // FIXME: support dynamic workspace loading.
66 let workspaces = match ws_worker.recv().unwrap() {
67 Ok(ws) => vec![ws],
68 Err(e) => {
69 log::warn!("loading workspace failed: {}", e);
70 Vec::new()
71 }
72 };
73 ws_worker.shutdown();
74 ws_watcher
75 .shutdown()
76 .map_err(|_| format_err!("ws watcher died"))?;
77 let mut state = ServerWorldState::new(ws_root.clone(), workspaces);
78
63 log::info!("server initialized, serving requests"); 79 log::info!("server initialized, serving requests");
64 let mut state = ServerWorldState::default();
65 80
66 let mut pending_requests = FxHashSet::default(); 81 let mut pending_requests = FxHashSet::default();
67 let mut subs = Subscriptions::new(); 82 let mut subs = Subscriptions::new();
68 let main_res = main_loop_inner( 83 let main_res = main_loop_inner(
69 internal_mode, 84 internal_mode,
70 publish_decorations, 85 publish_decorations,
71 root,
72 &pool, 86 &pool,
73 msg_sender, 87 msg_sender,
74 msg_receiver, 88 msg_receiver,
75 task_sender, 89 task_sender,
76 task_receiver.clone(), 90 task_receiver.clone(),
77 fs_worker,
78 ws_worker,
79 &mut state, 91 &mut state,
80 &mut pending_requests, 92 &mut pending_requests,
81 &mut subs, 93 &mut subs,
@@ -88,12 +100,11 @@ pub fn main_loop(
88 drop(pool); 100 drop(pool);
89 log::info!("...threadpool has finished"); 101 log::info!("...threadpool has finished");
90 102
91 let fs_res = fs_watcher.shutdown(); 103 let vfs = Arc::try_unwrap(state.vfs).expect("all snapshots should be dead");
92 let ws_res = ws_watcher.shutdown(); 104 let vfs_res = vfs.into_inner().shutdown();
93 105
94 main_res?; 106 main_res?;
95 fs_res.map_err(|_| format_err!("fs watcher died"))?; 107 vfs_res.map_err(|_| format_err!("fs watcher died"))?;
96 ws_res.map_err(|_| format_err!("ws watcher died"))?;
97 108
98 Ok(()) 109 Ok(())
99} 110}
@@ -101,28 +112,22 @@ pub fn main_loop(
101fn main_loop_inner( 112fn main_loop_inner(
102 internal_mode: bool, 113 internal_mode: bool,
103 publish_decorations: bool, 114 publish_decorations: bool,
104 ws_root: PathBuf,
105 pool: &ThreadPool, 115 pool: &ThreadPool,
106 msg_sender: &Sender<RawMessage>, 116 msg_sender: &Sender<RawMessage>,
107 msg_receiver: &Receiver<RawMessage>, 117 msg_receiver: &Receiver<RawMessage>,
108 task_sender: Sender<Task>, 118 task_sender: Sender<Task>,
109 task_receiver: Receiver<Task>, 119 task_receiver: Receiver<Task>,
110 fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
111 ws_worker: Worker<PathBuf, Result<CargoWorkspace>>,
112 state: &mut ServerWorldState, 120 state: &mut ServerWorldState,
113 pending_requests: &mut FxHashSet<u64>, 121 pending_requests: &mut FxHashSet<u64>,
114 subs: &mut Subscriptions, 122 subs: &mut Subscriptions,
115) -> Result<()> { 123) -> Result<()> {
116 let (libdata_sender, libdata_receiver) = unbounded(); 124 let (libdata_sender, libdata_receiver) = unbounded();
117 ws_worker.send(ws_root.clone());
118 fs_worker.send(ws_root.clone());
119 loop { 125 loop {
120 #[derive(Debug)] 126 #[derive(Debug)]
121 enum Event { 127 enum Event {
122 Msg(RawMessage), 128 Msg(RawMessage),
123 Task(Task), 129 Task(Task),
124 Fs(PathBuf, Vec<FileEvent>), 130 Vfs(VfsTask),
125 Ws(Result<CargoWorkspace>),
126 Lib(LibraryData), 131 Lib(LibraryData),
127 } 132 }
128 log::trace!("selecting"); 133 log::trace!("selecting");
@@ -132,77 +137,19 @@ fn main_loop_inner(
132 None => bail!("client exited without shutdown"), 137 None => bail!("client exited without shutdown"),
133 }, 138 },
134 recv(task_receiver, task) => Event::Task(task.unwrap()), 139 recv(task_receiver, task) => Event::Task(task.unwrap()),
135 recv(fs_worker.out, events) => match events { 140 recv(state.vfs.read().task_receiver(), task) => match task {
136 None => bail!("roots watcher died"), 141 None => bail!("vfs died"),
137 Some((pb, events)) => Event::Fs(pb, events), 142 Some(task) => Event::Vfs(task),
138 }
139 recv(ws_worker.out, ws) => match ws {
140 None => bail!("workspace watcher died"),
141 Some(ws) => Event::Ws(ws),
142 } 143 }
143 recv(libdata_receiver, data) => Event::Lib(data.unwrap()) 144 recv(libdata_receiver, data) => Event::Lib(data.unwrap())
144 }; 145 };
145 let mut state_changed = false; 146 let mut state_changed = false;
146 match event { 147 match event {
147 Event::Task(task) => on_task(task, msg_sender, pending_requests), 148 Event::Task(task) => on_task(task, msg_sender, pending_requests),
148 Event::Fs(root, events) => { 149 Event::Vfs(task) => {
149 log::info!("fs change, {}, {} events", root.display(), events.len()); 150 state.vfs.write().handle_task(task);
150 if root == ws_root {
151 state.apply_fs_changes(events);
152 } else {
153 let (files, resolver) = state.events_to_files(events);
154 let sender = libdata_sender.clone();
155 pool.execute(move || {
156 let start = ::std::time::Instant::now();
157 log::info!("indexing {} ... ", root.display());
158 let data = LibraryData::prepare(files, resolver);
159 log::info!("indexed {:?} {}", start.elapsed(), root.display());
160 sender.send(data);
161 });
162 }
163 state_changed = true; 151 state_changed = true;
164 } 152 }
165 Event::Ws(ws) => match ws {
166 Ok(ws) => {
167 let workspaces = vec![ws];
168 feedback(internal_mode, "workspace loaded", msg_sender);
169 for ws in workspaces.iter() {
170 // Add each library as constant input. If library is
171 // within the workspace, don't treat it as a library.
172 //
173 // HACK: If source roots are nested, pick the outer one.
174
175 let mut roots = ws
176 .packages()
177 .filter(|pkg| !pkg.is_member(ws))
178 .filter_map(|pkg| {
179 let root = pkg.root(ws).to_path_buf();
180 if root.starts_with(&ws_root) {
181 None
182 } else {
183 Some(root)
184 }
185 })
186 .collect::<Vec<_>>();
187 roots.sort_by_key(|it| it.as_os_str().len());
188 let unique = roots
189 .iter()
190 .enumerate()
191 .filter(|&(idx, long)| {
192 !roots[..idx].iter().any(|short| long.starts_with(short))
193 })
194 .map(|(_idx, root)| root);
195
196 for root in unique {
197 log::debug!("sending root, {}", root.display());
198 fs_worker.send(root.to_owned());
199 }
200 }
201 state.set_workspaces(workspaces);
202 state_changed = true;
203 }
204 Err(e) => log::warn!("loading workspace failed: {}", e),
205 },
206 Event::Lib(lib) => { 153 Event::Lib(lib) => {
207 feedback(internal_mode, "library loaded", msg_sender); 154 feedback(internal_mode, "library loaded", msg_sender);
208 state.add_lib(lib); 155 state.add_lib(lib);
@@ -234,6 +181,18 @@ fn main_loop_inner(
234 }, 181 },
235 }; 182 };
236 183
184 for lib in state.process_changes() {
185 let (root, files) = lib;
186 let sender = libdata_sender.clone();
187 pool.execute(move || {
188 let start = ::std::time::Instant::now();
189 log::info!("indexing {:?} ... ", root);
190 let data = LibraryData::prepare(root, files);
191 log::info!("indexed {:?} {:?}", start.elapsed(), root);
192 sender.send(data);
193 });
194 }
195
237 if state_changed { 196 if state_changed {
238 update_file_notifications_on_threadpool( 197 update_file_notifications_on_threadpool(
239 pool, 198 pool,
@@ -336,8 +295,13 @@ fn on_notification(
336 let path = uri 295 let path = uri
337 .to_file_path() 296 .to_file_path()
338 .map_err(|()| format_err!("invalid uri: {}", uri))?; 297 .map_err(|()| format_err!("invalid uri: {}", uri))?;
339 let file_id = state.add_mem_file(path, params.text_document.text); 298 if let Some(file_id) = state
340 subs.add_sub(file_id); 299 .vfs
300 .write()
301 .add_file_overlay(&path, params.text_document.text)
302 {
303 subs.add_sub(FileId(file_id.0));
304 }
341 return Ok(()); 305 return Ok(());
342 } 306 }
343 Err(not) => not, 307 Err(not) => not,
@@ -353,7 +317,7 @@ fn on_notification(
353 .pop() 317 .pop()
354 .ok_or_else(|| format_err!("empty changes"))? 318 .ok_or_else(|| format_err!("empty changes"))?
355 .text; 319 .text;
356 state.change_mem_file(path.as_path(), text)?; 320 state.vfs.write().change_file_overlay(path.as_path(), text);
357 return Ok(()); 321 return Ok(());
358 } 322 }
359 Err(not) => not, 323 Err(not) => not,
@@ -364,8 +328,9 @@ fn on_notification(
364 let path = uri 328 let path = uri
365 .to_file_path() 329 .to_file_path()
366 .map_err(|()| format_err!("invalid uri: {}", uri))?; 330 .map_err(|()| format_err!("invalid uri: {}", uri))?;
367 let file_id = state.remove_mem_file(path.as_path())?; 331 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
368 subs.remove_sub(file_id); 332 subs.remove_sub(FileId(file_id.0));
333 }
369 let params = req::PublishDiagnosticsParams { 334 let params = req::PublishDiagnosticsParams {
370 uri, 335 uri,
371 diagnostics: Vec::new(), 336 diagnostics: Vec::new(),