aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop/mod.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-15 15:24:20 +0100
committerAleksey Kladov <[email protected]>2018-08-15 15:24:20 +0100
commit9f6cf42c5fd0bd98dd3445239f2c6414e8fd9324 (patch)
tree5e6496a681a56e9fd1b6e6bae196538cd471e2d0 /crates/server/src/main_loop/mod.rs
parent109658332a75ca91d6dc2bf573e0ab77fa5619ca (diff)
Switch to file ids
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r--crates/server/src/main_loop/mod.rs78
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 @@
1mod handlers; 1mod handlers;
2 2
3use std::{ 3use std::{
4 path::PathBuf,
5 collections::{HashSet, HashMap}, 4 collections::{HashSet, HashMap},
6}; 5};
7 6
8use threadpool::ThreadPool; 7use threadpool::ThreadPool;
9use crossbeam_channel::{Sender, Receiver}; 8use crossbeam_channel::{Sender, Receiver};
10use languageserver_types::Url; 9use languageserver_types::Url;
11use libanalysis::{World, WorldState}; 10use libanalysis::{World, WorldState, FileId};
12use serde_json::to_value; 11use serde_json::to_value;
13 12
14use { 13use {
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(
133fn on_request( 136fn 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(
202fn on_notification( 207fn 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(
253fn handle_request_on_threadpool<R: req::ClientRequest>( 262fn 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>(
276fn update_file_notifications_on_threadpool( 287fn 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 }