aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-17 17:54:08 +0100
committerAleksey Kladov <[email protected]>2018-08-17 17:54:08 +0100
commited7ae78c6fd9e508f6e959c6a164cf8481f6b377 (patch)
tree556e8d4daffefa64dcdc5db8e75299514a0e85e4 /crates/server/src/main_loop
parent41570f60bf268c97223a864b8aa11a339929f55a (diff)
ServerWorld
Diffstat (limited to 'crates/server/src/main_loop')
-rw-r--r--crates/server/src/main_loop/handlers.rs102
-rw-r--r--crates/server/src/main_loop/mod.rs125
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};
8use libanalysis::{World, Query}; 8use libanalysis::{Query};
9use libeditor::{self, CursorPosition}; 9use libeditor::{self, CursorPosition};
10use libsyntax2::TextUnit; 10use libsyntax2::TextUnit;
11use serde_json::{to_value, from_value}; 11use serde_json::{to_value, from_value};
12 12
13use ::{ 13use ::{
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
19pub fn handle_syntax_tree( 19pub 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
29pub fn handle_extend_selection( 28pub 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
45pub fn handle_find_matching_brace( 43pub 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
64pub fn handle_document_symbol( 61pub 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
104pub fn handle_code_action( 100pub 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
129pub fn handle_workspace_symbol( 124pub 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
174pub fn handle_goto_definition( 168pub 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
194pub fn handle_execute_command( 187pub 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
267pub fn publish_diagnostics( 259pub 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
288pub fn publish_decorations( 279pub 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 @@
1mod handlers; 1mod handlers;
2 2
3use std::{ 3use std::{
4 collections::{HashSet, HashMap}, 4 collections::{HashSet},
5}; 5};
6 6
7use threadpool::ThreadPool; 7use threadpool::ThreadPool;
8use crossbeam_channel::{Sender, Receiver}; 8use crossbeam_channel::{Sender, Receiver};
9use languageserver_types::Url; 9use languageserver_types::Url;
10use libanalysis::{World, WorldState, FileId};
11use serde_json::to_value; 10use serde_json::to_value;
12 11
13use { 12use {
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
33pub(super) fn main_loop( 32pub(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
137fn on_request( 115fn 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
222fn on_notification( 195fn 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(
291fn handle_request_on_threadpool<R: req::ClientRequest>( 252fn 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
319fn update_file_notifications_on_threadpool( 275fn 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 }