diff options
author | Aleksey Kladov <[email protected]> | 2018-08-17 17:54:08 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-17 17:54:08 +0100 |
commit | ed7ae78c6fd9e508f6e959c6a164cf8481f6b377 (patch) | |
tree | 556e8d4daffefa64dcdc5db8e75299514a0e85e4 /crates/server/src/main_loop | |
parent | 41570f60bf268c97223a864b8aa11a339929f55a (diff) |
ServerWorld
Diffstat (limited to 'crates/server/src/main_loop')
-rw-r--r-- | crates/server/src/main_loop/handlers.rs | 102 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 125 |
2 files changed, 86 insertions, 141 deletions
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index f25c64c97..675f69bec 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs | |||
@@ -5,35 +5,33 @@ use languageserver_types::{ | |||
5 | Command, TextDocumentIdentifier, WorkspaceEdit, | 5 | Command, TextDocumentIdentifier, WorkspaceEdit, |
6 | SymbolInformation, Position, | 6 | SymbolInformation, Position, |
7 | }; | 7 | }; |
8 | use libanalysis::{World, Query}; | 8 | use libanalysis::{Query}; |
9 | use libeditor::{self, CursorPosition}; | 9 | use libeditor::{self, CursorPosition}; |
10 | use libsyntax2::TextUnit; | 10 | 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, | ||
15 | req::{self, Decoration}, Result, | 14 | req::{self, Decoration}, Result, |
16 | conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location}, | 15 | conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location}, |
16 | server_world::ServerWorld, | ||
17 | }; | 17 | }; |
18 | 18 | ||
19 | pub fn handle_syntax_tree( | 19 | pub fn handle_syntax_tree( |
20 | world: World, | 20 | world: ServerWorld, |
21 | path_map: PathMap, | ||
22 | params: req::SyntaxTreeParams, | 21 | params: req::SyntaxTreeParams, |
23 | ) -> Result<String> { | 22 | ) -> Result<String> { |
24 | let id = params.text_document.try_conv_with(&path_map)?; | 23 | let id = params.text_document.try_conv_with(&world)?; |
25 | let file = world.file_syntax(id)?; | 24 | let file = world.analysis().file_syntax(id)?; |
26 | Ok(libeditor::syntax_tree(&file)) | 25 | Ok(libeditor::syntax_tree(&file)) |
27 | } | 26 | } |
28 | 27 | ||
29 | pub fn handle_extend_selection( | 28 | pub fn handle_extend_selection( |
30 | world: World, | 29 | world: ServerWorld, |
31 | path_map: PathMap, | ||
32 | params: req::ExtendSelectionParams, | 30 | params: req::ExtendSelectionParams, |
33 | ) -> Result<req::ExtendSelectionResult> { | 31 | ) -> Result<req::ExtendSelectionResult> { |
34 | let file_id = params.text_document.try_conv_with(&path_map)?; | 32 | let file_id = params.text_document.try_conv_with(&world)?; |
35 | let file = world.file_syntax(file_id)?; | 33 | let file = world.analysis().file_syntax(file_id)?; |
36 | let line_index = world.file_line_index(file_id)?; | 34 | let line_index = world.analysis().file_line_index(file_id)?; |
37 | let selections = params.selections.into_iter() | 35 | let selections = params.selections.into_iter() |
38 | .map_conv_with(&line_index) | 36 | .map_conv_with(&line_index) |
39 | .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) | 37 | .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) |
@@ -43,13 +41,12 @@ pub fn handle_extend_selection( | |||
43 | } | 41 | } |
44 | 42 | ||
45 | pub fn handle_find_matching_brace( | 43 | pub fn handle_find_matching_brace( |
46 | world: World, | 44 | world: ServerWorld, |
47 | path_map: PathMap, | ||
48 | params: req::FindMatchingBraceParams, | 45 | params: req::FindMatchingBraceParams, |
49 | ) -> Result<Vec<Position>> { | 46 | ) -> Result<Vec<Position>> { |
50 | let file_id = params.text_document.try_conv_with(&path_map)?; | 47 | let file_id = params.text_document.try_conv_with(&world)?; |
51 | let file = world.file_syntax(file_id)?; | 48 | let file = world.analysis().file_syntax(file_id)?; |
52 | let line_index = world.file_line_index(file_id)?; | 49 | let line_index = world.analysis().file_line_index(file_id)?; |
53 | let res = params.offsets | 50 | let res = params.offsets |
54 | .into_iter() | 51 | .into_iter() |
55 | .map_conv_with(&line_index) | 52 | .map_conv_with(&line_index) |
@@ -62,13 +59,12 @@ pub fn handle_find_matching_brace( | |||
62 | } | 59 | } |
63 | 60 | ||
64 | pub fn handle_document_symbol( | 61 | pub fn handle_document_symbol( |
65 | world: World, | 62 | world: ServerWorld, |
66 | path_map: PathMap, | ||
67 | params: req::DocumentSymbolParams, | 63 | params: req::DocumentSymbolParams, |
68 | ) -> Result<Option<req::DocumentSymbolResponse>> { | 64 | ) -> Result<Option<req::DocumentSymbolResponse>> { |
69 | let file_id = params.text_document.try_conv_with(&path_map)?; | 65 | let file_id = params.text_document.try_conv_with(&world)?; |
70 | let file = world.file_syntax(file_id)?; | 66 | let file = world.analysis().file_syntax(file_id)?; |
71 | let line_index = world.file_line_index(file_id)?; | 67 | let line_index = world.analysis().file_line_index(file_id)?; |
72 | 68 | ||
73 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); | 69 | let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); |
74 | 70 | ||
@@ -102,13 +98,12 @@ pub fn handle_document_symbol( | |||
102 | } | 98 | } |
103 | 99 | ||
104 | pub fn handle_code_action( | 100 | pub fn handle_code_action( |
105 | world: World, | 101 | world: ServerWorld, |
106 | path_map: PathMap, | ||
107 | params: req::CodeActionParams, | 102 | params: req::CodeActionParams, |
108 | ) -> Result<Option<Vec<Command>>> { | 103 | ) -> Result<Option<Vec<Command>>> { |
109 | let file_id = params.text_document.try_conv_with(&path_map)?; | 104 | let file_id = params.text_document.try_conv_with(&world)?; |
110 | let file = world.file_syntax(file_id)?; | 105 | let file = world.analysis().file_syntax(file_id)?; |
111 | let line_index = world.file_line_index(file_id)?; | 106 | let line_index = world.analysis().file_line_index(file_id)?; |
112 | let offset = params.range.conv_with(&line_index).start(); | 107 | let offset = params.range.conv_with(&line_index).start(); |
113 | let mut ret = Vec::new(); | 108 | let mut ret = Vec::new(); |
114 | 109 | ||
@@ -127,8 +122,7 @@ pub fn handle_code_action( | |||
127 | } | 122 | } |
128 | 123 | ||
129 | pub fn handle_workspace_symbol( | 124 | pub fn handle_workspace_symbol( |
130 | world: World, | 125 | world: ServerWorld, |
131 | path_map: PathMap, | ||
132 | params: req::WorkspaceSymbolParams, | 126 | params: req::WorkspaceSymbolParams, |
133 | ) -> Result<Option<Vec<SymbolInformation>>> { | 127 | ) -> Result<Option<Vec<SymbolInformation>>> { |
134 | let all_symbols = params.query.contains("#"); | 128 | let all_symbols = params.query.contains("#"); |
@@ -143,25 +137,25 @@ pub fn handle_workspace_symbol( | |||
143 | q.limit(128); | 137 | q.limit(128); |
144 | q | 138 | q |
145 | }; | 139 | }; |
146 | let mut res = exec_query(&world, &path_map, query)?; | 140 | let mut res = exec_query(&world, query)?; |
147 | if res.is_empty() && !all_symbols { | 141 | if res.is_empty() && !all_symbols { |
148 | let mut query = Query::new(params.query); | 142 | let mut query = Query::new(params.query); |
149 | query.limit(128); | 143 | query.limit(128); |
150 | res = exec_query(&world, &path_map, query)?; | 144 | res = exec_query(&world, query)?; |
151 | } | 145 | } |
152 | 146 | ||
153 | return Ok(Some(res)); | 147 | return Ok(Some(res)); |
154 | 148 | ||
155 | fn exec_query(world: &World, path_map: &PathMap, query: Query) -> Result<Vec<SymbolInformation>> { | 149 | fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> { |
156 | let mut res = Vec::new(); | 150 | let mut res = Vec::new(); |
157 | for (file_id, symbol) in world.world_symbols(query) { | 151 | for (file_id, symbol) in world.analysis().world_symbols(query) { |
158 | let line_index = world.file_line_index(file_id)?; | 152 | let line_index = world.analysis().file_line_index(file_id)?; |
159 | let info = SymbolInformation { | 153 | let info = SymbolInformation { |
160 | name: symbol.name.to_string(), | 154 | name: symbol.name.to_string(), |
161 | kind: symbol.kind.conv(), | 155 | kind: symbol.kind.conv(), |
162 | location: to_location( | 156 | location: to_location( |
163 | file_id, symbol.node_range, | 157 | file_id, symbol.node_range, |
164 | path_map, &line_index | 158 | world, &line_index |
165 | )?, | 159 | )?, |
166 | container_name: None, | 160 | container_name: None, |
167 | }; | 161 | }; |
@@ -172,19 +166,18 @@ pub fn handle_workspace_symbol( | |||
172 | } | 166 | } |
173 | 167 | ||
174 | pub fn handle_goto_definition( | 168 | pub fn handle_goto_definition( |
175 | world: World, | 169 | world: ServerWorld, |
176 | path_map: PathMap, | ||
177 | params: req::TextDocumentPositionParams, | 170 | params: req::TextDocumentPositionParams, |
178 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 171 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
179 | let file_id = params.text_document.try_conv_with(&path_map)?; | 172 | let file_id = params.text_document.try_conv_with(&world)?; |
180 | let line_index = world.file_line_index(file_id)?; | 173 | let line_index = world.analysis().file_line_index(file_id)?; |
181 | let offset = params.position.conv_with(&line_index); | 174 | let offset = params.position.conv_with(&line_index); |
182 | let mut res = Vec::new(); | 175 | let mut res = Vec::new(); |
183 | for (file_id, symbol) in world.approximately_resolve_symbol(file_id, offset)? { | 176 | for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset)? { |
184 | let line_index = world.file_line_index(file_id)?; | 177 | let line_index = world.analysis().file_line_index(file_id)?; |
185 | let location = to_location( | 178 | let location = to_location( |
186 | file_id, symbol.node_range, | 179 | file_id, symbol.node_range, |
187 | &path_map, &line_index, | 180 | &world, &line_index, |
188 | )?; | 181 | )?; |
189 | res.push(location) | 182 | res.push(location) |
190 | } | 183 | } |
@@ -192,8 +185,7 @@ pub fn handle_goto_definition( | |||
192 | } | 185 | } |
193 | 186 | ||
194 | pub fn handle_execute_command( | 187 | pub fn handle_execute_command( |
195 | world: World, | 188 | world: ServerWorld, |
196 | path_map: PathMap, | ||
197 | mut params: req::ExecuteCommandParams, | 189 | mut params: req::ExecuteCommandParams, |
198 | ) -> Result<(req::ApplyWorkspaceEditParams, Option<Position>)> { | 190 | ) -> Result<(req::ApplyWorkspaceEditParams, Option<Position>)> { |
199 | if params.command.as_str() != "apply_code_action" { | 191 | if params.command.as_str() != "apply_code_action" { |
@@ -204,13 +196,13 @@ pub fn handle_execute_command( | |||
204 | } | 196 | } |
205 | let arg = params.arguments.pop().unwrap(); | 197 | let arg = params.arguments.pop().unwrap(); |
206 | let arg: ActionRequest = from_value(arg)?; | 198 | let arg: ActionRequest = from_value(arg)?; |
207 | let file_id = arg.text_document.try_conv_with(&path_map)?; | 199 | let file_id = arg.text_document.try_conv_with(&world)?; |
208 | let file = world.file_syntax(file_id)?; | 200 | let file = world.analysis().file_syntax(file_id)?; |
209 | let action_result = match arg.id { | 201 | let action_result = match arg.id { |
210 | ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|f| f()), | 202 | ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|f| f()), |
211 | ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|f| f()), | 203 | ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|f| f()), |
212 | }.ok_or_else(|| format_err!("command not applicable"))?; | 204 | }.ok_or_else(|| format_err!("command not applicable"))?; |
213 | let line_index = world.file_line_index(file_id)?; | 205 | let line_index = world.analysis().file_line_index(file_id)?; |
214 | let mut changes = HashMap::new(); | 206 | let mut changes = HashMap::new(); |
215 | changes.insert( | 207 | changes.insert( |
216 | arg.text_document.uri, | 208 | arg.text_document.uri, |
@@ -265,13 +257,12 @@ impl ActionId { | |||
265 | } | 257 | } |
266 | 258 | ||
267 | pub fn publish_diagnostics( | 259 | pub fn publish_diagnostics( |
268 | world: World, | 260 | world: ServerWorld, |
269 | path_map: PathMap, | ||
270 | uri: Url | 261 | uri: Url |
271 | ) -> Result<req::PublishDiagnosticsParams> { | 262 | ) -> Result<req::PublishDiagnosticsParams> { |
272 | let file_id = uri.try_conv_with(&path_map)?; | 263 | let file_id = world.uri_to_file_id(&uri)?; |
273 | let file = world.file_syntax(file_id)?; | 264 | let file = world.analysis().file_syntax(file_id)?; |
274 | let line_index = world.file_line_index(file_id)?; | 265 | let line_index = world.analysis().file_line_index(file_id)?; |
275 | let diagnostics = libeditor::diagnostics(&file) | 266 | let diagnostics = libeditor::diagnostics(&file) |
276 | .into_iter() | 267 | .into_iter() |
277 | .map(|d| Diagnostic { | 268 | .map(|d| Diagnostic { |
@@ -286,13 +277,12 @@ pub fn publish_diagnostics( | |||
286 | } | 277 | } |
287 | 278 | ||
288 | pub fn publish_decorations( | 279 | pub fn publish_decorations( |
289 | world: World, | 280 | world: ServerWorld, |
290 | path_map: PathMap, | ||
291 | uri: Url | 281 | uri: Url |
292 | ) -> Result<req::PublishDecorationsParams> { | 282 | ) -> Result<req::PublishDecorationsParams> { |
293 | let file_id = uri.try_conv_with(&path_map)?; | 283 | let file_id = world.uri_to_file_id(&uri)?; |
294 | let file = world.file_syntax(file_id)?; | 284 | let file = world.analysis().file_syntax(file_id)?; |
295 | let line_index = world.file_line_index(file_id)?; | 285 | let line_index = world.analysis().file_line_index(file_id)?; |
296 | let decorations = libeditor::highlight(&file) | 286 | let decorations = libeditor::highlight(&file) |
297 | .into_iter() | 287 | .into_iter() |
298 | .map(|h| Decoration { | 288 | .map(|h| Decoration { |
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 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | collections::{HashSet, HashMap}, | 4 | collections::{HashSet}, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use threadpool::ThreadPool; | 7 | use threadpool::ThreadPool; |
8 | use crossbeam_channel::{Sender, Receiver}; | 8 | use crossbeam_channel::{Sender, Receiver}; |
9 | use languageserver_types::Url; | 9 | use languageserver_types::Url; |
10 | use libanalysis::{World, WorldState, FileId}; | ||
11 | use serde_json::to_value; | 10 | use serde_json::to_value; |
12 | 11 | ||
13 | use { | 12 | use { |
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 | ||
33 | pub(super) fn main_loop( | 32 | pub(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 | ||
137 | fn on_request( | 115 | fn 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 | ||
222 | fn on_notification( | 195 | fn 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( | |||
291 | fn handle_request_on_threadpool<R: req::ClientRequest>( | 252 | fn 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 | ||
319 | fn update_file_notifications_on_threadpool( | 275 | fn 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 | } |