diff options
author | Aleksey Kladov <[email protected]> | 2018-08-15 15:24:20 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-15 15:24:20 +0100 |
commit | 9f6cf42c5fd0bd98dd3445239f2c6414e8fd9324 (patch) | |
tree | 5e6496a681a56e9fd1b6e6bae196538cd471e2d0 /crates/server/src/main_loop/mod.rs | |
parent | 109658332a75ca91d6dc2bf573e0ab77fa5619ca (diff) |
Switch to file ids
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 78 |
1 files changed, 45 insertions, 33 deletions
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index bc898c17b..2a31297be 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -1,22 +1,21 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | path::PathBuf, | ||
5 | collections::{HashSet, HashMap}, | 4 | collections::{HashSet, HashMap}, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use threadpool::ThreadPool; | 7 | use threadpool::ThreadPool; |
9 | use crossbeam_channel::{Sender, Receiver}; | 8 | use crossbeam_channel::{Sender, Receiver}; |
10 | use languageserver_types::Url; | 9 | use languageserver_types::Url; |
11 | use libanalysis::{World, WorldState}; | 10 | use libanalysis::{World, WorldState, FileId}; |
12 | use serde_json::to_value; | 11 | use serde_json::to_value; |
13 | 12 | ||
14 | use { | 13 | use { |
15 | req, dispatch, | 14 | req, dispatch, |
16 | Task, Result, | 15 | Task, Result, PathMap, |
17 | io::{Io, RawMsg, RawRequest, RawNotification}, | 16 | io::{Io, RawMsg, RawRequest, RawNotification}, |
18 | util::FilePath, | ||
19 | vfs::{FileEvent, FileEventKind}, | 17 | vfs::{FileEvent, FileEventKind}, |
18 | conv::TryConvWith, | ||
20 | main_loop::handlers::{ | 19 | main_loop::handlers::{ |
21 | handle_syntax_tree, | 20 | handle_syntax_tree, |
22 | handle_extend_selection, | 21 | handle_extend_selection, |
@@ -41,7 +40,8 @@ pub(super) fn main_loop( | |||
41 | info!("server initialized, serving requests"); | 40 | info!("server initialized, serving requests"); |
42 | let mut next_request_id = 0; | 41 | let mut next_request_id = 0; |
43 | let mut pending_requests: HashSet<u64> = HashSet::new(); | 42 | let mut pending_requests: HashSet<u64> = HashSet::new(); |
44 | let mut mem_map: HashMap<PathBuf, Option<String>> = HashMap::new(); | 43 | let mut path_map = PathMap::new(); |
44 | let mut mem_map: HashMap<FileId, Option<String>> = HashMap::new(); | ||
45 | let mut fs_events_receiver = Some(&fs_events_receiver); | 45 | let mut fs_events_receiver = Some(&fs_events_receiver); |
46 | loop { | 46 | loop { |
47 | enum Event { | 47 | enum Event { |
@@ -98,12 +98,15 @@ pub(super) fn main_loop( | |||
98 | }; | 98 | }; |
99 | (event.path, text) | 99 | (event.path, text) |
100 | }) | 100 | }) |
101 | .filter_map(|(path, text)| { | 101 | .map(|(path, text)| { |
102 | if mem_map.contains_key(path.as_path()) { | 102 | (path_map.get_or_insert(path), text) |
103 | mem_map.insert(path, text); | 103 | }) |
104 | .filter_map(|(id, text)| { | ||
105 | if mem_map.contains_key(&id) { | ||
106 | mem_map.insert(id, text); | ||
104 | None | 107 | None |
105 | } else { | 108 | } else { |
106 | Some((path, text)) | 109 | Some((id, text)) |
107 | } | 110 | } |
108 | }); | 111 | }); |
109 | 112 | ||
@@ -112,12 +115,12 @@ pub(super) fn main_loop( | |||
112 | Event::Msg(msg) => { | 115 | Event::Msg(msg) => { |
113 | match msg { | 116 | match msg { |
114 | RawMsg::Request(req) => { | 117 | RawMsg::Request(req) => { |
115 | if !on_request(io, world, pool, &task_sender, req)? { | 118 | if !on_request(io, world, &path_map, pool, &task_sender, req)? { |
116 | return Ok(()); | 119 | return Ok(()); |
117 | } | 120 | } |
118 | } | 121 | } |
119 | RawMsg::Notification(not) => { | 122 | RawMsg::Notification(not) => { |
120 | on_notification(io, world, pool, &task_sender, not, &mut mem_map)? | 123 | on_notification(io, world, &mut path_map, pool, &task_sender, not, &mut mem_map)? |
121 | } | 124 | } |
122 | RawMsg::Response(resp) => { | 125 | RawMsg::Response(resp) => { |
123 | if !pending_requests.remove(&resp.id) { | 126 | if !pending_requests.remove(&resp.id) { |
@@ -133,36 +136,38 @@ pub(super) fn main_loop( | |||
133 | fn on_request( | 136 | fn on_request( |
134 | io: &mut Io, | 137 | io: &mut Io, |
135 | world: &WorldState, | 138 | world: &WorldState, |
139 | path_map: &PathMap, | ||
136 | pool: &ThreadPool, | 140 | pool: &ThreadPool, |
137 | sender: &Sender<Task>, | 141 | sender: &Sender<Task>, |
138 | req: RawRequest, | 142 | req: RawRequest, |
139 | ) -> Result<bool> { | 143 | ) -> Result<bool> { |
140 | let mut req = Some(req); | 144 | let mut req = Some(req); |
141 | handle_request_on_threadpool::<req::SyntaxTree>( | 145 | handle_request_on_threadpool::<req::SyntaxTree>( |
142 | &mut req, pool, world, sender, handle_syntax_tree, | 146 | &mut req, pool, path_map, world, sender, handle_syntax_tree, |
143 | )?; | 147 | )?; |
144 | handle_request_on_threadpool::<req::ExtendSelection>( | 148 | handle_request_on_threadpool::<req::ExtendSelection>( |
145 | &mut req, pool, world, sender, handle_extend_selection, | 149 | &mut req, pool, path_map, world, sender, handle_extend_selection, |
146 | )?; | 150 | )?; |
147 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( | 151 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( |
148 | &mut req, pool, world, sender, handle_document_symbol, | 152 | &mut req, pool, path_map, world, sender, handle_document_symbol, |
149 | )?; | 153 | )?; |
150 | handle_request_on_threadpool::<req::CodeActionRequest>( | 154 | handle_request_on_threadpool::<req::CodeActionRequest>( |
151 | &mut req, pool, world, sender, handle_code_action, | 155 | &mut req, pool, path_map, world, sender, handle_code_action, |
152 | )?; | 156 | )?; |
153 | handle_request_on_threadpool::<req::WorkspaceSymbol>( | 157 | handle_request_on_threadpool::<req::WorkspaceSymbol>( |
154 | &mut req, pool, world, sender, handle_workspace_symbol, | 158 | &mut req, pool, path_map, world, sender, handle_workspace_symbol, |
155 | )?; | 159 | )?; |
156 | handle_request_on_threadpool::<req::GotoDefinition>( | 160 | handle_request_on_threadpool::<req::GotoDefinition>( |
157 | &mut req, pool, world, sender, handle_goto_definition, | 161 | &mut req, pool, path_map, world, sender, handle_goto_definition, |
158 | )?; | 162 | )?; |
159 | dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { | 163 | dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| { |
160 | io.send(RawMsg::Response(resp.into_response(Ok(None))?)); | 164 | io.send(RawMsg::Response(resp.into_response(Ok(None))?)); |
161 | 165 | ||
162 | let world = world.snapshot(); | 166 | let world = world.snapshot(); |
167 | let path_map = path_map.clone(); | ||
163 | let sender = sender.clone(); | 168 | let sender = sender.clone(); |
164 | pool.execute(move || { | 169 | pool.execute(move || { |
165 | let task = match handle_execute_command(world, params) { | 170 | let task = match handle_execute_command(world, path_map, params) { |
166 | Ok(req) => match to_value(req) { | 171 | Ok(req) => match to_value(req) { |
167 | Err(e) => Task::Die(e.into()), | 172 | Err(e) => Task::Die(e.into()), |
168 | Ok(params) => { | 173 | Ok(params) => { |
@@ -202,39 +207,43 @@ fn on_request( | |||
202 | fn on_notification( | 207 | fn on_notification( |
203 | io: &mut Io, | 208 | io: &mut Io, |
204 | world: &mut WorldState, | 209 | world: &mut WorldState, |
210 | path_map: &mut PathMap, | ||
205 | pool: &ThreadPool, | 211 | pool: &ThreadPool, |
206 | sender: &Sender<Task>, | 212 | sender: &Sender<Task>, |
207 | not: RawNotification, | 213 | not: RawNotification, |
208 | mem_map: &mut HashMap<PathBuf, Option<String>>, | 214 | mem_map: &mut HashMap<FileId, Option<String>>, |
209 | ) -> Result<()> { | 215 | ) -> Result<()> { |
210 | let mut not = Some(not); | 216 | let mut not = Some(not); |
211 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | 217 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
212 | let path = params.text_document.file_path()?; | 218 | let uri = params.text_document.uri; |
213 | mem_map.insert(path.clone(), None); | 219 | let path = uri.to_file_path() |
214 | world.change_file(path, Some(params.text_document.text)); | 220 | .map_err(|()| format_err!("invalid uri: {}", uri))?; |
221 | let file_id = path_map.get_or_insert(path); | ||
222 | mem_map.insert(file_id, None); | ||
223 | world.change_file(file_id, Some(params.text_document.text)); | ||
215 | update_file_notifications_on_threadpool( | 224 | update_file_notifications_on_threadpool( |
216 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | 225 | pool, world.snapshot(), path_map.clone(), sender.clone(), uri, |
217 | ); | 226 | ); |
218 | Ok(()) | 227 | Ok(()) |
219 | })?; | 228 | })?; |
220 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { | 229 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { |
221 | let path = params.text_document.file_path()?; | 230 | let file_id = params.text_document.try_conv_with(path_map)?; |
222 | let text = params.content_changes.pop() | 231 | let text = params.content_changes.pop() |
223 | .ok_or_else(|| format_err!("empty changes"))? | 232 | .ok_or_else(|| format_err!("empty changes"))? |
224 | .text; | 233 | .text; |
225 | world.change_file(path, Some(text)); | 234 | world.change_file(file_id, Some(text)); |
226 | update_file_notifications_on_threadpool( | 235 | update_file_notifications_on_threadpool( |
227 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | 236 | pool, world.snapshot(), path_map.clone(), sender.clone(), params.text_document.uri, |
228 | ); | 237 | ); |
229 | Ok(()) | 238 | Ok(()) |
230 | })?; | 239 | })?; |
231 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | 240 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { |
232 | let path = params.text_document.file_path()?; | 241 | let file_id = params.text_document.try_conv_with(path_map)?; |
233 | let text = match mem_map.remove(&path) { | 242 | let text = match mem_map.remove(&file_id) { |
234 | Some(text) => text, | 243 | Some(text) => text, |
235 | None => bail!("unmatched close notification"), | 244 | None => bail!("unmatched close notification"), |
236 | }; | 245 | }; |
237 | world.change_file(path, text); | 246 | world.change_file(file_id, text); |
238 | let not = req::PublishDiagnosticsParams { | 247 | let not = req::PublishDiagnosticsParams { |
239 | uri: params.text_document.uri, | 248 | uri: params.text_document.uri, |
240 | diagnostics: Vec::new(), | 249 | diagnostics: Vec::new(), |
@@ -253,16 +262,18 @@ fn on_notification( | |||
253 | fn handle_request_on_threadpool<R: req::ClientRequest>( | 262 | fn handle_request_on_threadpool<R: req::ClientRequest>( |
254 | req: &mut Option<RawRequest>, | 263 | req: &mut Option<RawRequest>, |
255 | pool: &ThreadPool, | 264 | pool: &ThreadPool, |
265 | path_map: &PathMap, | ||
256 | world: &WorldState, | 266 | world: &WorldState, |
257 | sender: &Sender<Task>, | 267 | sender: &Sender<Task>, |
258 | f: fn(World, R::Params) -> Result<R::Result>, | 268 | f: fn(World, PathMap, R::Params) -> Result<R::Result>, |
259 | ) -> Result<()> | 269 | ) -> Result<()> |
260 | { | 270 | { |
261 | dispatch::handle_request::<R, _>(req, |params, resp| { | 271 | dispatch::handle_request::<R, _>(req, |params, resp| { |
262 | let world = world.snapshot(); | 272 | let world = world.snapshot(); |
273 | let path_map = path_map.clone(); | ||
263 | let sender = sender.clone(); | 274 | let sender = sender.clone(); |
264 | pool.execute(move || { | 275 | pool.execute(move || { |
265 | let res = f(world, params); | 276 | let res = f(world, path_map, params); |
266 | let task = match resp.into_response(res) { | 277 | let task = match resp.into_response(res) { |
267 | Ok(resp) => Task::Respond(resp), | 278 | Ok(resp) => Task::Respond(resp), |
268 | Err(e) => Task::Die(e), | 279 | Err(e) => Task::Die(e), |
@@ -276,11 +287,12 @@ fn handle_request_on_threadpool<R: req::ClientRequest>( | |||
276 | fn update_file_notifications_on_threadpool( | 287 | fn update_file_notifications_on_threadpool( |
277 | pool: &ThreadPool, | 288 | pool: &ThreadPool, |
278 | world: World, | 289 | world: World, |
290 | path_map: PathMap, | ||
279 | sender: Sender<Task>, | 291 | sender: Sender<Task>, |
280 | uri: Url, | 292 | uri: Url, |
281 | ) { | 293 | ) { |
282 | pool.execute(move || { | 294 | pool.execute(move || { |
283 | match publish_diagnostics(world.clone(), uri.clone()) { | 295 | match publish_diagnostics(world.clone(), path_map.clone(), uri.clone()) { |
284 | Err(e) => { | 296 | Err(e) => { |
285 | error!("failed to compute diagnostics: {:?}", e) | 297 | error!("failed to compute diagnostics: {:?}", e) |
286 | } | 298 | } |
@@ -289,7 +301,7 @@ fn update_file_notifications_on_threadpool( | |||
289 | sender.send(Task::Notify(not)); | 301 | sender.send(Task::Notify(not)); |
290 | } | 302 | } |
291 | } | 303 | } |
292 | match publish_decorations(world, uri) { | 304 | match publish_decorations(world, path_map.clone(), uri) { |
293 | Err(e) => { | 305 | Err(e) => { |
294 | error!("failed to compute decorations: {:?}", e) | 306 | error!("failed to compute decorations: {:?}", e) |
295 | } | 307 | } |