aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop/mod.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-17 17:54:08 +0100
committerAleksey Kladov <[email protected]>2018-08-17 17:54:08 +0100
commited7ae78c6fd9e508f6e959c6a164cf8481f6b377 (patch)
tree556e8d4daffefa64dcdc5db8e75299514a0e85e4 /crates/server/src/main_loop/mod.rs
parent41570f60bf268c97223a864b8aa11a339929f55a (diff)
ServerWorld
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r--crates/server/src/main_loop/mod.rs125
1 files changed, 40 insertions, 85 deletions
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs
index a8340df59..ad7c480dc 100644
--- a/crates/server/src/main_loop/mod.rs
+++ b/crates/server/src/main_loop/mod.rs
@@ -1,21 +1,20 @@
1mod handlers; 1mod handlers;
2 2
3use std::{ 3use std::{
4 collections::{HashSet, HashMap}, 4 collections::{HashSet},
5}; 5};
6 6
7use threadpool::ThreadPool; 7use threadpool::ThreadPool;
8use crossbeam_channel::{Sender, Receiver}; 8use crossbeam_channel::{Sender, Receiver};
9use languageserver_types::Url; 9use languageserver_types::Url;
10use libanalysis::{World, WorldState, FileId};
11use serde_json::to_value; 10use serde_json::to_value;
12 11
13use { 12use {
14 req, dispatch, 13 req, dispatch,
15 Task, Result, PathMap, 14 Task, Result,
16 io::{Io, RawMsg, RawRequest, RawNotification}, 15 io::{Io, RawMsg, RawRequest, RawNotification},
17 vfs::{FileEvent, FileEventKind}, 16 vfs::FileEvent,
18 conv::TryConvWith, 17 server_world::{ServerWorldState, ServerWorld},
19 main_loop::handlers::{ 18 main_loop::handlers::{
20 handle_syntax_tree, 19 handle_syntax_tree,
21 handle_extend_selection, 20 handle_extend_selection,
@@ -32,17 +31,16 @@ use {
32 31
33pub(super) fn main_loop( 32pub(super) fn main_loop(
34 io: &mut Io, 33 io: &mut Io,
35 world: &mut WorldState,
36 pool: &mut ThreadPool, 34 pool: &mut ThreadPool,
37 task_sender: Sender<Task>, 35 task_sender: Sender<Task>,
38 task_receiver: Receiver<Task>, 36 task_receiver: Receiver<Task>,
39 fs_events_receiver: Receiver<Vec<FileEvent>>, 37 fs_events_receiver: Receiver<Vec<FileEvent>>,
40) -> Result<()> { 38) -> Result<()> {
41 info!("server initialized, serving requests"); 39 info!("server initialized, serving requests");
40 let mut state = ServerWorldState::new();
41
42 let mut next_request_id = 0; 42 let mut next_request_id = 0;
43 let mut pending_requests: HashSet<u64> = HashSet::new(); 43 let mut pending_requests: HashSet<u64> = HashSet::new();
44 let mut path_map = PathMap::new();
45 let mut mem_map: HashMap<FileId, Option<String>> = HashMap::new();
46 let mut fs_events_receiver = Some(&fs_events_receiver); 44 let mut fs_events_receiver = Some(&fs_events_receiver);
47 loop { 45 loop {
48 enum Event { 46 enum Event {
@@ -91,37 +89,17 @@ pub(super) fn main_loop(
91 } 89 }
92 Event::Fs(events) => { 90 Event::Fs(events) => {
93 trace!("fs change, {} events", events.len()); 91 trace!("fs change, {} events", events.len());
94 let changes = events.into_iter() 92 state.apply_fs_changes(events);
95 .map(|event| {
96 let text = match event.kind {
97 FileEventKind::Add(text) => Some(text),
98 FileEventKind::Remove => None,
99 };
100 (event.path, text)
101 })
102 .map(|(path, text)| {
103 (path_map.get_or_insert(path), text)
104 })
105 .filter_map(|(id, text)| {
106 if mem_map.contains_key(&id) {
107 mem_map.insert(id, text);
108 None
109 } else {
110 Some((id, text))
111 }
112 });
113
114 world.change_files(changes);
115 } 93 }
116 Event::Msg(msg) => { 94 Event::Msg(msg) => {
117 match msg { 95 match msg {
118 RawMsg::Request(req) => { 96 RawMsg::Request(req) => {
119 if !on_request(io, world, &path_map, pool, &task_sender, req)? { 97 if !on_request(io, &state, pool, &task_sender, req)? {
120 return Ok(()); 98 return Ok(());
121 } 99 }
122 } 100 }
123 RawMsg::Notification(not) => { 101 RawMsg::Notification(not) => {
124 on_notification(io, world, &mut path_map, pool, &task_sender, not, &mut mem_map)? 102 on_notification(io, &mut state, pool, &task_sender, not)?
125 } 103 }
126 RawMsg::Response(resp) => { 104 RawMsg::Response(resp) => {
127 if !pending_requests.remove(&resp.id) { 105 if !pending_requests.remove(&resp.id) {
@@ -136,45 +114,40 @@ pub(super) fn main_loop(
136 114
137fn on_request( 115fn on_request(
138 io: &mut Io, 116 io: &mut Io,
139 world: &WorldState, 117 world: &ServerWorldState,
140 path_map: &PathMap,
141 pool: &ThreadPool, 118 pool: &ThreadPool,
142 sender: &Sender<Task>, 119 sender: &Sender<Task>,
143 req: RawRequest, 120 req: RawRequest,
144) -> Result<bool> { 121) -> Result<bool> {
145 let mut req = Some(req); 122 let mut req = Some(req);
146 handle_request_on_threadpool::<req::SyntaxTree>( 123 handle_request_on_threadpool::<req::SyntaxTree>(
147 &mut req, pool, path_map, world, sender, handle_syntax_tree, 124 &mut req, pool, world, sender, handle_syntax_tree,
148 )?; 125 )?;
149 handle_request_on_threadpool::<req::ExtendSelection>( 126 handle_request_on_threadpool::<req::ExtendSelection>(
150 &mut req, pool, path_map, world, sender, handle_extend_selection, 127 &mut req, pool, world, sender, handle_extend_selection,
151 )?; 128 )?;
152 handle_request_on_threadpool::<req::FindMatchingBrace>( 129 handle_request_on_threadpool::<req::FindMatchingBrace>(
153 &mut req, pool, path_map, world, sender, handle_find_matching_brace, 130 &mut req, pool, world, sender, handle_find_matching_brace,
154 )?; 131 )?;
155 handle_request_on_threadpool::<req::DocumentSymbolRequest>( 132 handle_request_on_threadpool::<req::DocumentSymbolRequest>(
156 &mut req, pool, path_map, world, sender, handle_document_symbol, 133 &mut req, pool, world, sender, handle_document_symbol,
157 )?; 134 )?;
158 handle_request_on_threadpool::<req::CodeActionRequest>( 135 handle_request_on_threadpool::<req::CodeActionRequest>(
159 &mut req, pool, path_map, world, sender, handle_code_action, 136 &mut req, pool, world, sender, handle_code_action,
160 )?; 137 )?;
161 handle_request_on_threadpool::<req::WorkspaceSymbol>( 138 handle_request_on_threadpool::<req::WorkspaceSymbol>(
162 &mut req, pool, path_map, world, sender, handle_workspace_symbol, 139 &mut req, pool, world, sender, handle_workspace_symbol,
163 )?; 140 )?;
164 handle_request_on_threadpool::<req::GotoDefinition>( 141 handle_request_on_threadpool::<req::GotoDefinition>(
165 &mut req, pool, path_map, world, sender, handle_goto_definition, 142 &mut req, pool, world, sender, handle_goto_definition,
166 )?; 143 )?;
167 dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { 144 dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
168 io.send(RawMsg::Response(resp.into_response(Ok(None))?)); 145 io.send(RawMsg::Response(resp.into_response(Ok(None))?));
169 146
170 let world = world.snapshot({ 147 let world = world.snapshot();
171 let pm = path_map.clone();
172 move |id, path| pm.resolve(id, path)
173 });
174 let path_map = path_map.clone();
175 let sender = sender.clone(); 148 let sender = sender.clone();
176 pool.execute(move || { 149 pool.execute(move || {
177 let (edit, cursor) = match handle_execute_command(world, path_map, params) { 150 let (edit, cursor) = match handle_execute_command(world, params) {
178 Ok(res) => res, 151 Ok(res) => res,
179 Err(e) => return sender.send(Task::Die(e)), 152 Err(e) => return sender.send(Task::Die(e)),
180 }; 153 };
@@ -221,60 +194,48 @@ fn on_request(
221 194
222fn on_notification( 195fn on_notification(
223 io: &mut Io, 196 io: &mut Io,
224 world: &mut WorldState, 197 state: &mut ServerWorldState,
225 path_map: &mut PathMap,
226 pool: &ThreadPool, 198 pool: &ThreadPool,
227 sender: &Sender<Task>, 199 sender: &Sender<Task>,
228 not: RawNotification, 200 not: RawNotification,
229 mem_map: &mut HashMap<FileId, Option<String>>,
230) -> Result<()> { 201) -> Result<()> {
231 let mut not = Some(not); 202 let mut not = Some(not);
232 dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { 203 dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| {
233 let uri = params.text_document.uri; 204 let uri = params.text_document.uri;
234 let path = uri.to_file_path() 205 let path = uri.to_file_path()
235 .map_err(|()| format_err!("invalid uri: {}", uri))?; 206 .map_err(|()| format_err!("invalid uri: {}", uri))?;
236 let file_id = path_map.get_or_insert(path); 207 state.add_mem_file(path, params.text_document.text);
237 mem_map.insert(file_id, None);
238 world.change_file(file_id, Some(params.text_document.text));
239 update_file_notifications_on_threadpool( 208 update_file_notifications_on_threadpool(
240 pool, 209 pool,
241 world.snapshot({ 210 state.snapshot(),
242 let pm = path_map.clone();
243 move |id, path| pm.resolve(id, path)
244 }),
245 path_map.clone(),
246 sender.clone(), 211 sender.clone(),
247 uri, 212 uri,
248 ); 213 );
249 Ok(()) 214 Ok(())
250 })?; 215 })?;
251 dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { 216 dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| {
252 let file_id = params.text_document.try_conv_with(path_map)?; 217 let uri = params.text_document.uri;
218 let path = uri.to_file_path()
219 .map_err(|()| format_err!("invalid uri: {}", uri))?;
253 let text = params.content_changes.pop() 220 let text = params.content_changes.pop()
254 .ok_or_else(|| format_err!("empty changes"))? 221 .ok_or_else(|| format_err!("empty changes"))?
255 .text; 222 .text;
256 world.change_file(file_id, Some(text)); 223 state.change_mem_file(path.as_path(), text)?;
257 update_file_notifications_on_threadpool( 224 update_file_notifications_on_threadpool(
258 pool, 225 pool,
259 world.snapshot({ 226 state.snapshot(),
260 let pm = path_map.clone();
261 move |id, path| pm.resolve(id, path)
262 }),
263 path_map.clone(),
264 sender.clone(), 227 sender.clone(),
265 params.text_document.uri, 228 uri,
266 ); 229 );
267 Ok(()) 230 Ok(())
268 })?; 231 })?;
269 dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { 232 dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| {
270 let file_id = params.text_document.try_conv_with(path_map)?; 233 let uri = params.text_document.uri;
271 let text = match mem_map.remove(&file_id) { 234 let path = uri.to_file_path()
272 Some(text) => text, 235 .map_err(|()| format_err!("invalid uri: {}", uri))?;
273 None => bail!("unmatched close notification"), 236 state.remove_mem_file(path.as_path())?;
274 };
275 world.change_file(file_id, text);
276 let not = req::PublishDiagnosticsParams { 237 let not = req::PublishDiagnosticsParams {
277 uri: params.text_document.uri, 238 uri,
278 diagnostics: Vec::new(), 239 diagnostics: Vec::new(),
279 }; 240 };
280 let not = dispatch::send_notification::<req::PublishDiagnostics>(not); 241 let not = dispatch::send_notification::<req::PublishDiagnostics>(not);
@@ -291,21 +252,16 @@ fn on_notification(
291fn handle_request_on_threadpool<R: req::ClientRequest>( 252fn handle_request_on_threadpool<R: req::ClientRequest>(
292 req: &mut Option<RawRequest>, 253 req: &mut Option<RawRequest>,
293 pool: &ThreadPool, 254 pool: &ThreadPool,
294 path_map: &PathMap, 255 world: &ServerWorldState,
295 world: &WorldState,
296 sender: &Sender<Task>, 256 sender: &Sender<Task>,
297 f: fn(World, PathMap, R::Params) -> Result<R::Result>, 257 f: fn(ServerWorld, R::Params) -> Result<R::Result>,
298) -> Result<()> 258) -> Result<()>
299{ 259{
300 dispatch::handle_request::<R, _>(req, |params, resp| { 260 dispatch::handle_request::<R, _>(req, |params, resp| {
301 let world = world.snapshot({ 261 let world = world.snapshot();
302 let pm = path_map.clone();
303 move |id, path| pm.resolve(id, path)
304 });
305 let path_map = path_map.clone();
306 let sender = sender.clone(); 262 let sender = sender.clone();
307 pool.execute(move || { 263 pool.execute(move || {
308 let res = f(world, path_map, params); 264 let res = f(world, params);
309 let task = match resp.into_response(res) { 265 let task = match resp.into_response(res) {
310 Ok(resp) => Task::Respond(resp), 266 Ok(resp) => Task::Respond(resp),
311 Err(e) => Task::Die(e), 267 Err(e) => Task::Die(e),
@@ -318,13 +274,12 @@ fn handle_request_on_threadpool<R: req::ClientRequest>(
318 274
319fn update_file_notifications_on_threadpool( 275fn update_file_notifications_on_threadpool(
320 pool: &ThreadPool, 276 pool: &ThreadPool,
321 world: World, 277 world: ServerWorld,
322 path_map: PathMap,
323 sender: Sender<Task>, 278 sender: Sender<Task>,
324 uri: Url, 279 uri: Url,
325) { 280) {
326 pool.execute(move || { 281 pool.execute(move || {
327 match publish_diagnostics(world.clone(), path_map.clone(), uri.clone()) { 282 match publish_diagnostics(world.clone(), uri.clone()) {
328 Err(e) => { 283 Err(e) => {
329 error!("failed to compute diagnostics: {:?}", e) 284 error!("failed to compute diagnostics: {:?}", e)
330 } 285 }
@@ -333,7 +288,7 @@ fn update_file_notifications_on_threadpool(
333 sender.send(Task::Notify(not)); 288 sender.send(Task::Notify(not));
334 } 289 }
335 } 290 }
336 match publish_decorations(world, path_map.clone(), uri) { 291 match publish_decorations(world, uri) {
337 Err(e) => { 292 Err(e) => {
338 error!("failed to compute decorations: {:?}", e) 293 error!("failed to compute decorations: {:?}", e)
339 } 294 }