diff options
Diffstat (limited to 'crates/server/src/main_loop')
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 91 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 78 |
2 files changed, 101 insertions, 68 deletions
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 9de6f480b..637bf1b24 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs | |||
@@ -11,27 +11,29 @@ use libsyntax2::TextUnit; | |||
11 | use serde_json::{to_value, from_value}; | 11 | use serde_json::{to_value, from_value}; |
12 | 12 | ||
13 | use ::{ | 13 | use ::{ |
14 | PathMap, | ||
14 | req::{self, Decoration}, Result, | 15 | req::{self, Decoration}, Result, |
15 | util::FilePath, | 16 | conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location}, |
16 | conv::{Conv, ConvWith, TryConvWith, MapConvWith}, | ||
17 | }; | 17 | }; |
18 | 18 | ||
19 | pub fn handle_syntax_tree( | 19 | pub fn handle_syntax_tree( |
20 | world: World, | 20 | world: World, |
21 | path_map: PathMap, | ||
21 | params: req::SyntaxTreeParams, | 22 | params: req::SyntaxTreeParams, |
22 | ) -> Result<String> { | 23 | ) -> Result<String> { |
23 | let path = params.text_document.file_path()?; | 24 | let id = params.text_document.try_conv_with(&path_map)?; |
24 | let file = world.file_syntax(&path)?; | 25 | let file = world.file_syntax(id)?; |
25 | Ok(libeditor::syntax_tree(&file)) | 26 | Ok(libeditor::syntax_tree(&file)) |
26 | } | 27 | } |
27 | 28 | ||
28 | pub fn handle_extend_selection( | 29 | pub fn handle_extend_selection( |
29 | world: World, | 30 | world: World, |
31 | path_map: PathMap, | ||
30 | params: req::ExtendSelectionParams, | 32 | params: req::ExtendSelectionParams, |
31 | ) -> Result<req::ExtendSelectionResult> { | 33 | ) -> Result<req::ExtendSelectionResult> { |
32 | let path = params.text_document.file_path()?; | 34 | let file_id = params.text_document.try_conv_with(&path_map)?; |
33 | let file = world.file_syntax(&path)?; | 35 | let file = world.file_syntax(file_id)?; |
34 | let line_index = world.file_line_index(&path)?; | 36 | let line_index = world.file_line_index(file_id)?; |
35 | let selections = params.selections.into_iter() | 37 | let selections = params.selections.into_iter() |
36 | .map_conv_with(&line_index) | 38 | .map_conv_with(&line_index) |
37 | .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) | 39 | .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) |
@@ -42,11 +44,12 @@ pub fn handle_extend_selection( | |||
42 | 44 | ||
43 | pub fn handle_document_symbol( | 45 | pub fn handle_document_symbol( |
44 | world: World, | 46 | world: World, |
47 | path_map: PathMap, | ||
45 | params: req::DocumentSymbolParams, | 48 | params: req::DocumentSymbolParams, |
46 | ) -> Result<Option<req::DocumentSymbolResponse>> { | 49 | ) -> Result<Option<req::DocumentSymbolResponse>> { |
47 | let path = params.text_document.file_path()?; | 50 | let file_id = params.text_document.try_conv_with(&path_map)?; |
48 | let file = world.file_syntax(&path)?; | 51 | let file = world.file_syntax(file_id)?; |
49 | let line_index = world.file_line_index(&path)?; | 52 | let line_index = world.file_line_index(file_id)?; |
50 | 53 | ||
51 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); | 54 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); |
52 | 55 | ||
@@ -81,11 +84,12 @@ pub fn handle_document_symbol( | |||
81 | 84 | ||
82 | pub fn handle_code_action( | 85 | pub fn handle_code_action( |
83 | world: World, | 86 | world: World, |
87 | path_map: PathMap, | ||
84 | params: req::CodeActionParams, | 88 | params: req::CodeActionParams, |
85 | ) -> Result<Option<Vec<Command>>> { | 89 | ) -> Result<Option<Vec<Command>>> { |
86 | let path = params.text_document.file_path()?; | 90 | let file_id = params.text_document.try_conv_with(&path_map)?; |
87 | let file = world.file_syntax(&path)?; | 91 | let file = world.file_syntax(file_id)?; |
88 | let line_index = world.file_line_index(&path)?; | 92 | let line_index = world.file_line_index(file_id)?; |
89 | let offset = params.range.conv_with(&line_index).start(); | 93 | let offset = params.range.conv_with(&line_index).start(); |
90 | let mut ret = Vec::new(); | 94 | let mut ret = Vec::new(); |
91 | 95 | ||
@@ -105,6 +109,7 @@ pub fn handle_code_action( | |||
105 | 109 | ||
106 | pub fn handle_workspace_symbol( | 110 | pub fn handle_workspace_symbol( |
107 | world: World, | 111 | world: World, |
112 | path_map: PathMap, | ||
108 | params: req::WorkspaceSymbolParams, | 113 | params: req::WorkspaceSymbolParams, |
109 | ) -> Result<Option<Vec<SymbolInformation>>> { | 114 | ) -> Result<Option<Vec<SymbolInformation>>> { |
110 | let all_symbols = params.query.contains("#"); | 115 | let all_symbols = params.query.contains("#"); |
@@ -119,23 +124,26 @@ pub fn handle_workspace_symbol( | |||
119 | q.limit(128); | 124 | q.limit(128); |
120 | q | 125 | q |
121 | }; | 126 | }; |
122 | let mut res = exec_query(&world, query)?; | 127 | let mut res = exec_query(&world, &path_map, query)?; |
123 | if res.is_empty() && !all_symbols { | 128 | if res.is_empty() && !all_symbols { |
124 | let mut query = Query::new(params.query); | 129 | let mut query = Query::new(params.query); |
125 | query.limit(128); | 130 | query.limit(128); |
126 | res = exec_query(&world, query)?; | 131 | res = exec_query(&world, &path_map, query)?; |
127 | } | 132 | } |
128 | 133 | ||
129 | return Ok(Some(res)); | 134 | return Ok(Some(res)); |
130 | 135 | ||
131 | fn exec_query(world: &World, query: Query) -> Result<Vec<SymbolInformation>> { | 136 | fn exec_query(world: &World, path_map: &PathMap, query: Query) -> Result<Vec<SymbolInformation>> { |
132 | let mut res = Vec::new(); | 137 | let mut res = Vec::new(); |
133 | for (path, symbol) in world.world_symbols(query) { | 138 | for (file_id, symbol) in world.world_symbols(query) { |
134 | let line_index = world.file_line_index(path)?; | 139 | let line_index = world.file_line_index(file_id)?; |
135 | let info = SymbolInformation { | 140 | let info = SymbolInformation { |
136 | name: symbol.name.to_string(), | 141 | name: symbol.name.to_string(), |
137 | kind: symbol.kind.conv(), | 142 | kind: symbol.kind.conv(), |
138 | location: (path, symbol.node_range).try_conv_with(&line_index)?, | 143 | location: to_location( |
144 | file_id, symbol.node_range, | ||
145 | path_map, &line_index | ||
146 | )?, | ||
139 | container_name: None, | 147 | container_name: None, |
140 | }; | 148 | }; |
141 | res.push(info); | 149 | res.push(info); |
@@ -146,15 +154,19 @@ pub fn handle_workspace_symbol( | |||
146 | 154 | ||
147 | pub fn handle_goto_definition( | 155 | pub fn handle_goto_definition( |
148 | world: World, | 156 | world: World, |
157 | path_map: PathMap, | ||
149 | params: req::TextDocumentPositionParams, | 158 | params: req::TextDocumentPositionParams, |
150 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 159 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
151 | let path = params.text_document.file_path()?; | 160 | let file_id = params.text_document.try_conv_with(&path_map)?; |
152 | let line_index = world.file_line_index(&path)?; | 161 | let line_index = world.file_line_index(file_id)?; |
153 | let offset = params.position.conv_with(&line_index); | 162 | let offset = params.position.conv_with(&line_index); |
154 | let mut res = Vec::new(); | 163 | let mut res = Vec::new(); |
155 | for (path, symbol) in world.approximately_resolve_symbol(&path, offset)? { | 164 | for (file_id, symbol) in world.approximately_resolve_symbol(file_id, offset)? { |
156 | let line_index = world.file_line_index(path)?; | 165 | let line_index = world.file_line_index(file_id)?; |
157 | let location = (path, symbol.node_range).try_conv_with(&line_index)?; | 166 | let location = to_location( |
167 | file_id, symbol.node_range, | ||
168 | &path_map, &line_index, | ||
169 | )?; | ||
158 | res.push(location) | 170 | res.push(location) |
159 | } | 171 | } |
160 | Ok(Some(req::GotoDefinitionResponse::Array(res))) | 172 | Ok(Some(req::GotoDefinitionResponse::Array(res))) |
@@ -162,6 +174,7 @@ pub fn handle_goto_definition( | |||
162 | 174 | ||
163 | pub fn handle_execute_command( | 175 | pub fn handle_execute_command( |
164 | world: World, | 176 | world: World, |
177 | path_map: PathMap, | ||
165 | mut params: req::ExecuteCommandParams, | 178 | mut params: req::ExecuteCommandParams, |
166 | ) -> Result<req::ApplyWorkspaceEditParams> { | 179 | ) -> Result<req::ApplyWorkspaceEditParams> { |
167 | if params.command.as_str() != "apply_code_action" { | 180 | if params.command.as_str() != "apply_code_action" { |
@@ -172,8 +185,8 @@ pub fn handle_execute_command( | |||
172 | } | 185 | } |
173 | let arg = params.arguments.pop().unwrap(); | 186 | let arg = params.arguments.pop().unwrap(); |
174 | let arg: ActionRequest = from_value(arg)?; | 187 | let arg: ActionRequest = from_value(arg)?; |
175 | let path = arg.text_document.file_path()?; | 188 | let file_id = arg.text_document.try_conv_with(&path_map)?; |
176 | let file = world.file_syntax(&path)?; | 189 | let file = world.file_syntax(file_id)?; |
177 | let edit = match arg.id { | 190 | let edit = match arg.id { |
178 | ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|edit| edit()), | 191 | ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|edit| edit()), |
179 | ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|edit| edit()), | 192 | ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|edit| edit()), |
@@ -182,7 +195,7 @@ pub fn handle_execute_command( | |||
182 | Some(edit) => edit, | 195 | Some(edit) => edit, |
183 | None => bail!("command not applicable"), | 196 | None => bail!("command not applicable"), |
184 | }; | 197 | }; |
185 | let line_index = world.file_line_index(&path)?; | 198 | let line_index = world.file_line_index(file_id)?; |
186 | let mut changes = HashMap::new(); | 199 | let mut changes = HashMap::new(); |
187 | changes.insert( | 200 | changes.insert( |
188 | arg.text_document.uri, | 201 | arg.text_document.uri, |
@@ -231,10 +244,14 @@ impl ActionId { | |||
231 | } | 244 | } |
232 | } | 245 | } |
233 | 246 | ||
234 | pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> { | 247 | pub fn publish_diagnostics( |
235 | let path = uri.file_path()?; | 248 | world: World, |
236 | let file = world.file_syntax(&path)?; | 249 | path_map: PathMap, |
237 | let line_index = world.file_line_index(&path)?; | 250 | uri: Url |
251 | ) -> Result<req::PublishDiagnosticsParams> { | ||
252 | let file_id = uri.try_conv_with(&path_map)?; | ||
253 | let file = world.file_syntax(file_id)?; | ||
254 | let line_index = world.file_line_index(file_id)?; | ||
238 | let diagnostics = libeditor::diagnostics(&file) | 255 | let diagnostics = libeditor::diagnostics(&file) |
239 | .into_iter() | 256 | .into_iter() |
240 | .map(|d| Diagnostic { | 257 | .map(|d| Diagnostic { |
@@ -248,10 +265,14 @@ pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnos | |||
248 | Ok(req::PublishDiagnosticsParams { uri, diagnostics }) | 265 | Ok(req::PublishDiagnosticsParams { uri, diagnostics }) |
249 | } | 266 | } |
250 | 267 | ||
251 | pub fn publish_decorations(world: World, uri: Url) -> Result<req::PublishDecorationsParams> { | 268 | pub fn publish_decorations( |
252 | let path = uri.file_path()?; | 269 | world: World, |
253 | let file = world.file_syntax(&path)?; | 270 | path_map: PathMap, |
254 | let line_index = world.file_line_index(&path)?; | 271 | uri: Url |
272 | ) -> Result<req::PublishDecorationsParams> { | ||
273 | let file_id = uri.try_conv_with(&path_map)?; | ||
274 | let file = world.file_syntax(file_id)?; | ||
275 | let line_index = world.file_line_index(file_id)?; | ||
255 | let decorations = libeditor::highlight(&file) | 276 | let decorations = libeditor::highlight(&file) |
256 | .into_iter() | 277 | .into_iter() |
257 | .map(|h| Decoration { | 278 | .map(|h| Decoration { |
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 | } |