diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/libanalysis/src/imp.rs | 11 | ||||
-rw-r--r-- | crates/libanalysis/src/job.rs | 4 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/server/src/dispatch.rs | 18 | ||||
-rw-r--r-- | crates/server/src/main.rs | 5 | ||||
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 25 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 108 |
7 files changed, 119 insertions, 60 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 97802bd50..6a6e1e933 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -23,6 +23,7 @@ use { | |||
23 | module_map::Problem, | 23 | module_map::Problem, |
24 | symbol_index::FileSymbols, | 24 | symbol_index::FileSymbols, |
25 | module_map::{ModuleMap, ChangeKind}, | 25 | module_map::{ModuleMap, ChangeKind}, |
26 | JobToken, | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | #[derive(Debug)] | 29 | #[derive(Debug)] |
@@ -111,9 +112,10 @@ impl AnalysisImpl { | |||
111 | .clone() | 112 | .clone() |
112 | } | 113 | } |
113 | 114 | ||
114 | pub fn world_symbols(&self, mut query: Query) -> Vec<(FileId, FileSymbol)> { | 115 | pub fn world_symbols(&self, mut query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
115 | self.reindex(); | 116 | self.reindex(); |
116 | self.data.file_map.iter() | 117 | self.data.file_map.iter() |
118 | .take_while(move |_| !token.is_canceled()) | ||
117 | .flat_map(move |(id, data)| { | 119 | .flat_map(move |(id, data)| { |
118 | let symbols = data.symbols(); | 120 | let symbols = data.symbols(); |
119 | query.process(symbols).into_iter().map(move |s| (*id, s)) | 121 | query.process(symbols).into_iter().map(move |s| (*id, s)) |
@@ -147,11 +149,12 @@ impl AnalysisImpl { | |||
147 | &self, | 149 | &self, |
148 | id: FileId, | 150 | id: FileId, |
149 | offset: TextUnit, | 151 | offset: TextUnit, |
152 | token: &JobToken, | ||
150 | ) -> Vec<(FileId, FileSymbol)> { | 153 | ) -> Vec<(FileId, FileSymbol)> { |
151 | let file = self.file_syntax(id); | 154 | let file = self.file_syntax(id); |
152 | let syntax = file.syntax(); | 155 | let syntax = file.syntax(); |
153 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 156 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
154 | return self.index_resolve(name_ref); | 157 | return self.index_resolve(name_ref, token); |
155 | } | 158 | } |
156 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { | 159 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { |
157 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 160 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
@@ -245,12 +248,12 @@ impl AnalysisImpl { | |||
245 | .collect() | 248 | .collect() |
246 | } | 249 | } |
247 | 250 | ||
248 | fn index_resolve(&self, name_ref: ast::NameRef) -> Vec<(FileId, FileSymbol)> { | 251 | fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
249 | let name = name_ref.text(); | 252 | let name = name_ref.text(); |
250 | let mut query = Query::new(name.to_string()); | 253 | let mut query = Query::new(name.to_string()); |
251 | query.exact(); | 254 | query.exact(); |
252 | query.limit(4); | 255 | query.limit(4); |
253 | self.world_symbols(query) | 256 | self.world_symbols(query, token) |
254 | } | 257 | } |
255 | 258 | ||
256 | fn resolve_module(&self, id: FileId, module: ast::Module) -> Vec<FileId> { | 259 | fn resolve_module(&self, id: FileId, module: ast::Module) -> Vec<FileId> { |
diff --git a/crates/libanalysis/src/job.rs b/crates/libanalysis/src/job.rs index 4d393b915..ea1652a26 100644 --- a/crates/libanalysis/src/job.rs +++ b/crates/libanalysis/src/job.rs | |||
@@ -18,8 +18,8 @@ impl JobHandle { | |||
18 | let handle = JobHandle { job_alive: receiver_alive, _job_canceled: sender_canceled }; | 18 | let handle = JobHandle { job_alive: receiver_alive, _job_canceled: sender_canceled }; |
19 | (handle, token) | 19 | (handle, token) |
20 | } | 20 | } |
21 | pub fn is_alive(&self) -> bool { | 21 | pub fn has_completed(&self) -> bool { |
22 | !is_closed(&self.job_alive) | 22 | is_closed(&self.job_alive) |
23 | } | 23 | } |
24 | pub fn cancel(self) { | 24 | pub fn cancel(self) { |
25 | } | 25 | } |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 20ddb69d6..a59fd1c09 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -159,11 +159,11 @@ impl Analysis { | |||
159 | let file = self.file_syntax(file_id); | 159 | let file = self.file_syntax(file_id); |
160 | libeditor::file_structure(&file) | 160 | libeditor::file_structure(&file) |
161 | } | 161 | } |
162 | pub fn symbol_search(&self, query: Query) -> Vec<(FileId, FileSymbol)> { | 162 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
163 | self.imp.world_symbols(query) | 163 | self.imp.world_symbols(query, token) |
164 | } | 164 | } |
165 | pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, FileSymbol)> { | 165 | pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
166 | self.imp.approximately_resolve_symbol(file_id, offset) | 166 | self.imp.approximately_resolve_symbol(file_id, offset, token) |
167 | } | 167 | } |
168 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 168 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
169 | self.imp.parent_module(file_id) | 169 | self.imp.parent_module(file_id) |
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs index d8cca48d0..806534944 100644 --- a/crates/server/src/dispatch.rs +++ b/crates/server/src/dispatch.rs | |||
@@ -58,20 +58,18 @@ fn parse_request_as<R: ClientRequest>(raw: RawRequest) | |||
58 | Ok(Ok((params, responder))) | 58 | Ok(Ok((params, responder))) |
59 | } | 59 | } |
60 | 60 | ||
61 | pub fn handle_request<R, F>(req: &mut Option<RawRequest>, f: F) -> Result<()> | 61 | pub fn handle_request<R, F>(req: RawRequest, f: F) -> Result<::std::result::Result<u64, RawRequest>> |
62 | where | 62 | where |
63 | R: ClientRequest, | 63 | R: ClientRequest, |
64 | F: FnOnce(R::Params, Responder<R>) -> Result<()> | 64 | F: FnOnce(R::Params, Responder<R>) -> Result<()> |
65 | { | 65 | { |
66 | match req.take() { | 66 | let id = req.id; |
67 | None => Ok(()), | 67 | match parse_request_as::<R>(req)? { |
68 | Some(r) => match parse_request_as::<R>(r)? { | 68 | Ok((params, responder)) => { |
69 | Ok((params, responder)) => f(params, responder), | 69 | let () = f(params, responder)?; |
70 | Err(r) => { | 70 | Ok(Ok(id)) |
71 | *req = Some(r); | 71 | }, |
72 | Ok(()) | 72 | Err(r) => Ok(Err(r)), |
73 | } | ||
74 | } | ||
75 | } | 73 | } |
76 | } | 74 | } |
77 | 75 | ||
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 6af8bf81b..eeb343b80 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs | |||
@@ -84,14 +84,13 @@ fn initialize(io: &mut Io) -> Result<()> { | |||
84 | bail!("expected initialize request, got {:?}", res), | 84 | bail!("expected initialize request, got {:?}", res), |
85 | 85 | ||
86 | RawMsg::Request(req) => { | 86 | RawMsg::Request(req) => { |
87 | let mut req = Some(req); | 87 | let req = dispatch::handle_request::<req::Initialize, _>(req, |_params, resp| { |
88 | dispatch::handle_request::<req::Initialize, _>(&mut req, |_params, resp| { | ||
89 | let res = req::InitializeResult { capabilities: caps::server_capabilities() }; | 88 | let res = req::InitializeResult { capabilities: caps::server_capabilities() }; |
90 | let resp = resp.into_response(Ok(res))?; | 89 | let resp = resp.into_response(Ok(res))?; |
91 | io.send(RawMsg::Response(resp)); | 90 | io.send(RawMsg::Response(resp)); |
92 | Ok(()) | 91 | Ok(()) |
93 | })?; | 92 | })?; |
94 | if let Some(req) = req { | 93 | if let Err(req) = req { |
95 | bail!("expected initialize request, got {:?}", req) | 94 | bail!("expected initialize request, got {:?}", req) |
96 | } | 95 | } |
97 | match io.recv()? { | 96 | match io.recv()? { |
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 6b70399b0..ab8b6f799 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs | |||
@@ -7,7 +7,7 @@ use languageserver_types::{ | |||
7 | CompletionItem, InsertTextFormat, CompletionItemKind, | 7 | CompletionItem, InsertTextFormat, CompletionItemKind, |
8 | }; | 8 | }; |
9 | use serde_json::to_value; | 9 | use serde_json::to_value; |
10 | use libanalysis::{Query, FileId, RunnableKind}; | 10 | use libanalysis::{Query, FileId, RunnableKind, JobToken}; |
11 | use libsyntax2::{ | 11 | use libsyntax2::{ |
12 | text_utils::contains_offset_nonstrict, | 12 | text_utils::contains_offset_nonstrict, |
13 | }; | 13 | }; |
@@ -21,6 +21,7 @@ use ::{ | |||
21 | pub fn handle_syntax_tree( | 21 | pub fn handle_syntax_tree( |
22 | world: ServerWorld, | 22 | world: ServerWorld, |
23 | params: req::SyntaxTreeParams, | 23 | params: req::SyntaxTreeParams, |
24 | _token: JobToken, | ||
24 | ) -> Result<String> { | 25 | ) -> Result<String> { |
25 | let id = params.text_document.try_conv_with(&world)?; | 26 | let id = params.text_document.try_conv_with(&world)?; |
26 | let res = world.analysis().syntax_tree(id); | 27 | let res = world.analysis().syntax_tree(id); |
@@ -30,6 +31,7 @@ pub fn handle_syntax_tree( | |||
30 | pub fn handle_extend_selection( | 31 | pub fn handle_extend_selection( |
31 | world: ServerWorld, | 32 | world: ServerWorld, |
32 | params: req::ExtendSelectionParams, | 33 | params: req::ExtendSelectionParams, |
34 | _token: JobToken, | ||
33 | ) -> Result<req::ExtendSelectionResult> { | 35 | ) -> Result<req::ExtendSelectionResult> { |
34 | let file_id = params.text_document.try_conv_with(&world)?; | 36 | let file_id = params.text_document.try_conv_with(&world)?; |
35 | let file = world.analysis().file_syntax(file_id); | 37 | let file = world.analysis().file_syntax(file_id); |
@@ -45,6 +47,7 @@ pub fn handle_extend_selection( | |||
45 | pub fn handle_find_matching_brace( | 47 | pub fn handle_find_matching_brace( |
46 | world: ServerWorld, | 48 | world: ServerWorld, |
47 | params: req::FindMatchingBraceParams, | 49 | params: req::FindMatchingBraceParams, |
50 | _token: JobToken, | ||
48 | ) -> Result<Vec<Position>> { | 51 | ) -> Result<Vec<Position>> { |
49 | let file_id = params.text_document.try_conv_with(&world)?; | 52 | let file_id = params.text_document.try_conv_with(&world)?; |
50 | let file = world.analysis().file_syntax(file_id); | 53 | let file = world.analysis().file_syntax(file_id); |
@@ -63,6 +66,7 @@ pub fn handle_find_matching_brace( | |||
63 | pub fn handle_join_lines( | 66 | pub fn handle_join_lines( |
64 | world: ServerWorld, | 67 | world: ServerWorld, |
65 | params: req::JoinLinesParams, | 68 | params: req::JoinLinesParams, |
69 | _token: JobToken, | ||
66 | ) -> Result<req::SourceChange> { | 70 | ) -> Result<req::SourceChange> { |
67 | let file_id = params.text_document.try_conv_with(&world)?; | 71 | let file_id = params.text_document.try_conv_with(&world)?; |
68 | let line_index = world.analysis().file_line_index(file_id); | 72 | let line_index = world.analysis().file_line_index(file_id); |
@@ -74,6 +78,7 @@ pub fn handle_join_lines( | |||
74 | pub fn handle_on_type_formatting( | 78 | pub fn handle_on_type_formatting( |
75 | world: ServerWorld, | 79 | world: ServerWorld, |
76 | params: req::DocumentOnTypeFormattingParams, | 80 | params: req::DocumentOnTypeFormattingParams, |
81 | _token: JobToken, | ||
77 | ) -> Result<Option<Vec<TextEdit>>> { | 82 | ) -> Result<Option<Vec<TextEdit>>> { |
78 | if params.ch != "=" { | 83 | if params.ch != "=" { |
79 | return Ok(None); | 84 | return Ok(None); |
@@ -93,6 +98,7 @@ pub fn handle_on_type_formatting( | |||
93 | pub fn handle_document_symbol( | 98 | pub fn handle_document_symbol( |
94 | world: ServerWorld, | 99 | world: ServerWorld, |
95 | params: req::DocumentSymbolParams, | 100 | params: req::DocumentSymbolParams, |
101 | _token: JobToken, | ||
96 | ) -> Result<Option<req::DocumentSymbolResponse>> { | 102 | ) -> Result<Option<req::DocumentSymbolResponse>> { |
97 | let file_id = params.text_document.try_conv_with(&world)?; | 103 | let file_id = params.text_document.try_conv_with(&world)?; |
98 | let line_index = world.analysis().file_line_index(file_id); | 104 | let line_index = world.analysis().file_line_index(file_id); |
@@ -131,6 +137,7 @@ pub fn handle_document_symbol( | |||
131 | pub fn handle_workspace_symbol( | 137 | pub fn handle_workspace_symbol( |
132 | world: ServerWorld, | 138 | world: ServerWorld, |
133 | params: req::WorkspaceSymbolParams, | 139 | params: req::WorkspaceSymbolParams, |
140 | token: JobToken, | ||
134 | ) -> Result<Option<Vec<SymbolInformation>>> { | 141 | ) -> Result<Option<Vec<SymbolInformation>>> { |
135 | let all_symbols = params.query.contains("#"); | 142 | let all_symbols = params.query.contains("#"); |
136 | let query = { | 143 | let query = { |
@@ -144,18 +151,18 @@ pub fn handle_workspace_symbol( | |||
144 | q.limit(128); | 151 | q.limit(128); |
145 | q | 152 | q |
146 | }; | 153 | }; |
147 | let mut res = exec_query(&world, query)?; | 154 | let mut res = exec_query(&world, query, &token)?; |
148 | if res.is_empty() && !all_symbols { | 155 | if res.is_empty() && !all_symbols { |
149 | let mut query = Query::new(params.query); | 156 | let mut query = Query::new(params.query); |
150 | query.limit(128); | 157 | query.limit(128); |
151 | res = exec_query(&world, query)?; | 158 | res = exec_query(&world, query, &token)?; |
152 | } | 159 | } |
153 | 160 | ||
154 | return Ok(Some(res)); | 161 | return Ok(Some(res)); |
155 | 162 | ||
156 | fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> { | 163 | fn exec_query(world: &ServerWorld, query: Query, token: &JobToken) -> Result<Vec<SymbolInformation>> { |
157 | let mut res = Vec::new(); | 164 | let mut res = Vec::new(); |
158 | for (file_id, symbol) in world.analysis().symbol_search(query) { | 165 | for (file_id, symbol) in world.analysis().symbol_search(query, token) { |
159 | let line_index = world.analysis().file_line_index(file_id); | 166 | let line_index = world.analysis().file_line_index(file_id); |
160 | let info = SymbolInformation { | 167 | let info = SymbolInformation { |
161 | name: symbol.name.to_string(), | 168 | name: symbol.name.to_string(), |
@@ -175,12 +182,13 @@ pub fn handle_workspace_symbol( | |||
175 | pub fn handle_goto_definition( | 182 | pub fn handle_goto_definition( |
176 | world: ServerWorld, | 183 | world: ServerWorld, |
177 | params: req::TextDocumentPositionParams, | 184 | params: req::TextDocumentPositionParams, |
185 | token: JobToken, | ||
178 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 186 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
179 | let file_id = params.text_document.try_conv_with(&world)?; | 187 | let file_id = params.text_document.try_conv_with(&world)?; |
180 | let line_index = world.analysis().file_line_index(file_id); | 188 | let line_index = world.analysis().file_line_index(file_id); |
181 | let offset = params.position.conv_with(&line_index); | 189 | let offset = params.position.conv_with(&line_index); |
182 | let mut res = Vec::new(); | 190 | let mut res = Vec::new(); |
183 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset) { | 191 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset, &token) { |
184 | let line_index = world.analysis().file_line_index(file_id); | 192 | let line_index = world.analysis().file_line_index(file_id); |
185 | let location = to_location( | 193 | let location = to_location( |
186 | file_id, symbol.node_range, | 194 | file_id, symbol.node_range, |
@@ -194,6 +202,7 @@ pub fn handle_goto_definition( | |||
194 | pub fn handle_parent_module( | 202 | pub fn handle_parent_module( |
195 | world: ServerWorld, | 203 | world: ServerWorld, |
196 | params: TextDocumentIdentifier, | 204 | params: TextDocumentIdentifier, |
205 | _token: JobToken, | ||
197 | ) -> Result<Vec<Location>> { | 206 | ) -> Result<Vec<Location>> { |
198 | let file_id = params.try_conv_with(&world)?; | 207 | let file_id = params.try_conv_with(&world)?; |
199 | let mut res = Vec::new(); | 208 | let mut res = Vec::new(); |
@@ -211,6 +220,7 @@ pub fn handle_parent_module( | |||
211 | pub fn handle_runnables( | 220 | pub fn handle_runnables( |
212 | world: ServerWorld, | 221 | world: ServerWorld, |
213 | params: req::RunnablesParams, | 222 | params: req::RunnablesParams, |
223 | _token: JobToken, | ||
214 | ) -> Result<Vec<req::Runnable>> { | 224 | ) -> Result<Vec<req::Runnable>> { |
215 | let file_id = params.text_document.try_conv_with(&world)?; | 225 | let file_id = params.text_document.try_conv_with(&world)?; |
216 | let line_index = world.analysis().file_line_index(file_id); | 226 | let line_index = world.analysis().file_line_index(file_id); |
@@ -260,6 +270,7 @@ pub fn handle_runnables( | |||
260 | pub fn handle_decorations( | 270 | pub fn handle_decorations( |
261 | world: ServerWorld, | 271 | world: ServerWorld, |
262 | params: TextDocumentIdentifier, | 272 | params: TextDocumentIdentifier, |
273 | _token: JobToken, | ||
263 | ) -> Result<Vec<Decoration>> { | 274 | ) -> Result<Vec<Decoration>> { |
264 | let file_id = params.try_conv_with(&world)?; | 275 | let file_id = params.try_conv_with(&world)?; |
265 | Ok(highlight(&world, file_id)) | 276 | Ok(highlight(&world, file_id)) |
@@ -268,6 +279,7 @@ pub fn handle_decorations( | |||
268 | pub fn handle_completion( | 279 | pub fn handle_completion( |
269 | world: ServerWorld, | 280 | world: ServerWorld, |
270 | params: req::CompletionParams, | 281 | params: req::CompletionParams, |
282 | _token: JobToken, | ||
271 | ) -> Result<Option<req::CompletionResponse>> { | 283 | ) -> Result<Option<req::CompletionResponse>> { |
272 | let file_id = params.text_document.try_conv_with(&world)?; | 284 | let file_id = params.text_document.try_conv_with(&world)?; |
273 | let line_index = world.analysis().file_line_index(file_id); | 285 | let line_index = world.analysis().file_line_index(file_id); |
@@ -297,6 +309,7 @@ pub fn handle_completion( | |||
297 | pub fn handle_code_action( | 309 | pub fn handle_code_action( |
298 | world: ServerWorld, | 310 | world: ServerWorld, |
299 | params: req::CodeActionParams, | 311 | params: req::CodeActionParams, |
312 | _token: JobToken, | ||
300 | ) -> Result<Option<Vec<Command>>> { | 313 | ) -> Result<Option<Vec<Command>>> { |
301 | let file_id = params.text_document.try_conv_with(&world)?; | 314 | let file_id = params.text_document.try_conv_with(&world)?; |
302 | let line_index = world.analysis().file_line_index(file_id); | 315 | let line_index = world.analysis().file_line_index(file_id); |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index cd17cab56..db7d5ae34 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -2,12 +2,13 @@ mod handlers; | |||
2 | mod subscriptions; | 2 | mod subscriptions; |
3 | 3 | ||
4 | use std::{ | 4 | use std::{ |
5 | collections::{HashSet}, | 5 | collections::{HashMap}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use threadpool::ThreadPool; | 8 | use threadpool::ThreadPool; |
9 | use crossbeam_channel::{Sender, Receiver}; | 9 | use crossbeam_channel::{Sender, Receiver}; |
10 | use libanalysis::FileId; | 10 | use languageserver_types::{NumberOrString}; |
11 | use libanalysis::{FileId, JobHandle, JobToken}; | ||
11 | 12 | ||
12 | use { | 13 | use { |
13 | req, dispatch, | 14 | req, dispatch, |
@@ -28,7 +29,7 @@ pub(super) fn main_loop( | |||
28 | info!("server initialized, serving requests"); | 29 | info!("server initialized, serving requests"); |
29 | let mut state = ServerWorldState::new(); | 30 | let mut state = ServerWorldState::new(); |
30 | 31 | ||
31 | let mut pending_requests: HashSet<u64> = HashSet::new(); | 32 | let mut pending_requests: HashMap<u64, JobHandle> = HashMap::new(); |
32 | let mut fs_events_receiver = Some(&fs_events_receiver); | 33 | let mut fs_events_receiver = Some(&fs_events_receiver); |
33 | let mut subs = Subscriptions::new(); | 34 | let mut subs = Subscriptions::new(); |
34 | loop { | 35 | loop { |
@@ -61,8 +62,12 @@ pub(super) fn main_loop( | |||
61 | } | 62 | } |
62 | Event::Task(task) => { | 63 | Event::Task(task) => { |
63 | match task { | 64 | match task { |
64 | Task::Respond(response) => | 65 | Task::Respond(response) => { |
65 | io.send(RawMsg::Response(response)), | 66 | if let Some(handle) = pending_requests.remove(&response.id) { |
67 | assert!(handle.has_completed()); | ||
68 | } | ||
69 | io.send(RawMsg::Response(response)) | ||
70 | } | ||
66 | Task::Notify(n) => | 71 | Task::Notify(n) => |
67 | io.send(RawMsg::Notification(n)), | 72 | io.send(RawMsg::Notification(n)), |
68 | Task::Die(error) => | 73 | Task::Die(error) => |
@@ -78,18 +83,16 @@ pub(super) fn main_loop( | |||
78 | Event::Msg(msg) => { | 83 | Event::Msg(msg) => { |
79 | match msg { | 84 | match msg { |
80 | RawMsg::Request(req) => { | 85 | RawMsg::Request(req) => { |
81 | if !on_request(io, &mut state, pool, &task_sender, req)? { | 86 | if !on_request(io, &mut state, &mut pending_requests, pool, &task_sender, req)? { |
82 | return Ok(()); | 87 | return Ok(()); |
83 | } | 88 | } |
84 | } | 89 | } |
85 | RawMsg::Notification(not) => { | 90 | RawMsg::Notification(not) => { |
86 | on_notification(io, &mut state, &mut subs, not)?; | 91 | on_notification(io, &mut state, &mut pending_requests, &mut subs, not)?; |
87 | state_changed = true; | 92 | state_changed = true; |
88 | } | 93 | } |
89 | RawMsg::Response(resp) => { | 94 | RawMsg::Response(resp) => { |
90 | if !pending_requests.remove(&resp.id) { | 95 | error!("unexpected response: {:?}", resp) |
91 | error!("unexpected response: {:?}", resp) | ||
92 | } | ||
93 | } | 96 | } |
94 | } | 97 | } |
95 | } | 98 | } |
@@ -109,15 +112,17 @@ pub(super) fn main_loop( | |||
109 | fn on_request( | 112 | fn on_request( |
110 | io: &mut Io, | 113 | io: &mut Io, |
111 | world: &mut ServerWorldState, | 114 | world: &mut ServerWorldState, |
115 | pending_requests: &mut HashMap<u64, JobHandle>, | ||
112 | pool: &ThreadPool, | 116 | pool: &ThreadPool, |
113 | sender: &Sender<Task>, | 117 | sender: &Sender<Task>, |
114 | req: RawRequest, | 118 | req: RawRequest, |
115 | ) -> Result<bool> { | 119 | ) -> Result<bool> { |
116 | let mut pool_dispatcher = PoolDispatcher { | 120 | let mut pool_dispatcher = PoolDispatcher { |
117 | req: Some(req), | 121 | req: Some(req), |
122 | res: None, | ||
118 | pool, world, sender | 123 | pool, world, sender |
119 | }; | 124 | }; |
120 | pool_dispatcher | 125 | let req = pool_dispatcher |
121 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? | 126 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? |
122 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? | 127 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? |
123 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? | 128 | .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)? |
@@ -130,23 +135,30 @@ fn on_request( | |||
130 | .on::<req::Runnables>(handlers::handle_runnables)? | 135 | .on::<req::Runnables>(handlers::handle_runnables)? |
131 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 136 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
132 | .on::<req::Completion>(handlers::handle_completion)? | 137 | .on::<req::Completion>(handlers::handle_completion)? |
133 | .on::<req::CodeActionRequest>(handlers::handle_code_action)?; | 138 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? |
134 | 139 | .finish(); | |
135 | let mut req = pool_dispatcher.req; | 140 | match req { |
136 | let mut shutdown = false; | 141 | Ok((id, handle)) => { |
137 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { | 142 | let inserted = pending_requests.insert(id, handle).is_none(); |
138 | let resp = resp.into_response(Ok(()))?; | 143 | assert!(inserted, "duplicate request: {}", id); |
139 | io.send(RawMsg::Response(resp)); | 144 | }, |
140 | shutdown = true; | 145 | Err(req) => { |
141 | Ok(()) | 146 | let req = dispatch::handle_request::<req::Shutdown, _>(req, |(), resp| { |
142 | })?; | 147 | let resp = resp.into_response(Ok(()))?; |
143 | if shutdown { | 148 | io.send(RawMsg::Response(resp)); |
144 | info!("lifecycle: initiating shutdown"); | 149 | Ok(()) |
145 | return Ok(false); | 150 | })?; |
146 | } | 151 | match req { |
147 | if let Some(req) = req { | 152 | Ok(_id) => { |
148 | error!("unknown method: {:?}", req); | 153 | info!("lifecycle: initiating shutdown"); |
149 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); | 154 | return Ok(false); |
155 | } | ||
156 | Err(req) => { | ||
157 | error!("unknown method: {:?}", req); | ||
158 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); | ||
159 | } | ||
160 | } | ||
161 | } | ||
150 | } | 162 | } |
151 | Ok(true) | 163 | Ok(true) |
152 | } | 164 | } |
@@ -154,10 +166,23 @@ fn on_request( | |||
154 | fn on_notification( | 166 | fn on_notification( |
155 | io: &mut Io, | 167 | io: &mut Io, |
156 | state: &mut ServerWorldState, | 168 | state: &mut ServerWorldState, |
169 | pending_requests: &mut HashMap<u64, JobHandle>, | ||
157 | subs: &mut Subscriptions, | 170 | subs: &mut Subscriptions, |
158 | not: RawNotification, | 171 | not: RawNotification, |
159 | ) -> Result<()> { | 172 | ) -> Result<()> { |
160 | let mut not = Some(not); | 173 | let mut not = Some(not); |
174 | dispatch::handle_notification::<req::Cancel, _>(&mut not, |params| { | ||
175 | let id = match params.id { | ||
176 | NumberOrString::Number(id) => id, | ||
177 | NumberOrString::String(id) => { | ||
178 | panic!("string id's not supported: {:?}", id); | ||
179 | } | ||
180 | }; | ||
181 | if let Some(handle) = pending_requests.remove(&id) { | ||
182 | handle.cancel(); | ||
183 | } | ||
184 | Ok(()) | ||
185 | })?; | ||
161 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | 186 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
162 | let uri = params.text_document.uri; | 187 | let uri = params.text_document.uri; |
163 | let path = uri.to_file_path() | 188 | let path = uri.to_file_path() |
@@ -196,21 +221,30 @@ fn on_notification( | |||
196 | 221 | ||
197 | struct PoolDispatcher<'a> { | 222 | struct PoolDispatcher<'a> { |
198 | req: Option<RawRequest>, | 223 | req: Option<RawRequest>, |
224 | res: Option<(u64, JobHandle)>, | ||
199 | pool: &'a ThreadPool, | 225 | pool: &'a ThreadPool, |
200 | world: &'a ServerWorldState, | 226 | world: &'a ServerWorldState, |
201 | sender: &'a Sender<Task>, | 227 | sender: &'a Sender<Task>, |
202 | } | 228 | } |
203 | 229 | ||
204 | impl<'a> PoolDispatcher<'a> { | 230 | impl<'a> PoolDispatcher<'a> { |
205 | fn on<'b, R: req::ClientRequest>(&'b mut self, f: fn(ServerWorld, R::Params) -> Result<R::Result>) -> Result<&'b mut Self> { | 231 | fn on<'b, R: req::ClientRequest>( |
232 | &'b mut self, | ||
233 | f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result> | ||
234 | ) -> Result<&'b mut Self> { | ||
235 | let req = match self.req.take() { | ||
236 | None => return Ok(self), | ||
237 | Some(req) => req, | ||
238 | }; | ||
206 | let world = self.world; | 239 | let world = self.world; |
207 | let sender = self.sender; | 240 | let sender = self.sender; |
208 | let pool = self.pool; | 241 | let pool = self.pool; |
209 | dispatch::handle_request::<R, _>(&mut self.req, |params, resp| { | 242 | let (handle, token) = JobHandle::new(); |
243 | let req = dispatch::handle_request::<R, _>(req, |params, resp| { | ||
210 | let world = world.snapshot(); | 244 | let world = world.snapshot(); |
211 | let sender = sender.clone(); | 245 | let sender = sender.clone(); |
212 | pool.execute(move || { | 246 | pool.execute(move || { |
213 | let res = f(world, params); | 247 | let res = f(world, params, token); |
214 | let task = match resp.into_response(res) { | 248 | let task = match resp.into_response(res) { |
215 | Ok(resp) => Task::Respond(resp), | 249 | Ok(resp) => Task::Respond(resp), |
216 | Err(e) => Task::Die(e), | 250 | Err(e) => Task::Die(e), |
@@ -219,8 +253,20 @@ impl<'a> PoolDispatcher<'a> { | |||
219 | }); | 253 | }); |
220 | Ok(()) | 254 | Ok(()) |
221 | })?; | 255 | })?; |
256 | match req { | ||
257 | Ok(id) => self.res = Some((id, handle)), | ||
258 | Err(req) => self.req = Some(req), | ||
259 | } | ||
222 | Ok(self) | 260 | Ok(self) |
223 | } | 261 | } |
262 | |||
263 | fn finish(&mut self) -> ::std::result::Result<(u64, JobHandle), RawRequest> { | ||
264 | match (self.res.take(), self.req.take()) { | ||
265 | (Some(res), None) => Ok(res), | ||
266 | (None, Some(req)) => Err(req), | ||
267 | _ => unreachable!(), | ||
268 | } | ||
269 | } | ||
224 | } | 270 | } |
225 | 271 | ||
226 | fn update_file_notifications_on_threadpool( | 272 | fn update_file_notifications_on_threadpool( |