diff options
-rw-r--r-- | crates/server/src/main.rs | 3 | ||||
-rw-r--r-- | crates/server/src/main_loop/mod.rs | 196 |
2 files changed, 119 insertions, 80 deletions
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 4b250acfa..7416de08a 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs | |||
@@ -31,7 +31,7 @@ use flexi_logger::Logger; | |||
31 | use libanalysis::WorldState; | 31 | use libanalysis::WorldState; |
32 | 32 | ||
33 | use ::{ | 33 | use ::{ |
34 | io::{Io, RawMsg, RawResponse, RawNotification} | 34 | io::{Io, RawMsg, RawResponse, RawRequest, RawNotification} |
35 | }; | 35 | }; |
36 | 36 | ||
37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
@@ -104,6 +104,7 @@ fn initialize(io: &mut Io) -> Result<()> { | |||
104 | 104 | ||
105 | enum Task { | 105 | enum Task { |
106 | Respond(RawResponse), | 106 | Respond(RawResponse), |
107 | Request(RawRequest), | ||
107 | Notify(RawNotification), | 108 | Notify(RawNotification), |
108 | Die(::failure::Error), | 109 | Die(::failure::Error), |
109 | } | 110 | } |
diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index e80b9988d..3d367f5f6 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs | |||
@@ -1,13 +1,16 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | 2 | ||
3 | use std::collections::HashSet; | ||
4 | |||
3 | use threadpool::ThreadPool; | 5 | use threadpool::ThreadPool; |
4 | use crossbeam_channel::{Sender, Receiver}; | 6 | use crossbeam_channel::{Sender, Receiver}; |
5 | use languageserver_types::Url; | 7 | use languageserver_types::Url; |
6 | use libanalysis::{World, WorldState}; | 8 | use libanalysis::{World, WorldState}; |
9 | |||
7 | use { | 10 | use { |
8 | req, dispatch, | 11 | req, dispatch, |
9 | Task, Result, | 12 | Task, Result, |
10 | io::{Io, RawMsg, RawRequest}, | 13 | io::{Io, RawMsg, RawRequest, RawNotification}, |
11 | util::FilePath, | 14 | util::FilePath, |
12 | main_loop::handlers::{ | 15 | main_loop::handlers::{ |
13 | handle_syntax_tree, | 16 | handle_syntax_tree, |
@@ -27,6 +30,8 @@ pub(super) fn main_loop( | |||
27 | receiver: Receiver<Task>, | 30 | receiver: Receiver<Task>, |
28 | ) -> Result<()> { | 31 | ) -> Result<()> { |
29 | info!("server initialized, serving requests"); | 32 | info!("server initialized, serving requests"); |
33 | let mut next_request_id = 0; | ||
34 | let mut pending_requests: HashSet<u64> = HashSet::new(); | ||
30 | loop { | 35 | loop { |
31 | enum Event { | 36 | enum Event { |
32 | Msg(RawMsg), | 37 | Msg(RawMsg), |
@@ -48,6 +53,12 @@ pub(super) fn main_loop( | |||
48 | } | 53 | } |
49 | Event::Task(task) => { | 54 | Event::Task(task) => { |
50 | match task { | 55 | match task { |
56 | Task::Request(mut request) => { | ||
57 | request.id = next_request_id; | ||
58 | pending_requests.insert(next_request_id); | ||
59 | next_request_id += 1; | ||
60 | io.send(RawMsg::Request(request)); | ||
61 | } | ||
51 | Task::Respond(response) => | 62 | Task::Respond(response) => |
52 | io.send(RawMsg::Response(response)), | 63 | io.send(RawMsg::Response(response)), |
53 | Task::Notify(n) => | 64 | Task::Notify(n) => |
@@ -58,97 +69,124 @@ pub(super) fn main_loop( | |||
58 | continue; | 69 | continue; |
59 | } | 70 | } |
60 | Event::Msg(msg) => { | 71 | Event::Msg(msg) => { |
61 | if !on_msg(io, world, pool, &sender, msg)? { | 72 | match msg { |
62 | return Ok(()); | 73 | RawMsg::Request(req) => { |
74 | if !on_request(io, world, pool, &sender, req)? { | ||
75 | return Ok(()); | ||
76 | } | ||
77 | } | ||
78 | RawMsg::Notification(not) => { | ||
79 | on_notification(io, world, pool, &sender, not)? | ||
80 | } | ||
81 | RawMsg::Response(resp) => { | ||
82 | error!("unexpected response: {:?}", resp) | ||
83 | } | ||
63 | } | 84 | } |
64 | } | 85 | } |
65 | }; | 86 | }; |
66 | } | 87 | } |
67 | } | 88 | } |
68 | 89 | ||
69 | fn on_msg( | 90 | fn on_request( |
70 | io: &mut Io, | 91 | io: &mut Io, |
71 | world: &mut WorldState, | 92 | world: &WorldState, |
72 | pool: &mut ThreadPool, | 93 | pool: &ThreadPool, |
73 | sender: &Sender<Task>, | 94 | sender: &Sender<Task>, |
74 | msg: RawMsg, | 95 | req: RawRequest, |
75 | ) -> Result<bool> { | 96 | ) -> Result<bool> { |
76 | match msg { | 97 | let mut req = Some(req); |
77 | RawMsg::Request(req) => { | 98 | handle_request_on_threadpool::<req::SyntaxTree>( |
78 | let mut req = Some(req); | 99 | &mut req, pool, world, sender, handle_syntax_tree, |
79 | handle_request_on_threadpool::<req::SyntaxTree>( | 100 | )?; |
80 | &mut req, pool, world, sender, handle_syntax_tree, | 101 | handle_request_on_threadpool::<req::ExtendSelection>( |
81 | )?; | 102 | &mut req, pool, world, sender, handle_extend_selection, |
82 | handle_request_on_threadpool::<req::ExtendSelection>( | 103 | )?; |
83 | &mut req, pool, world, sender, handle_extend_selection, | 104 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( |
84 | )?; | 105 | &mut req, pool, world, sender, handle_document_symbol, |
85 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( | 106 | )?; |
86 | &mut req, pool, world, sender, handle_document_symbol, | 107 | handle_request_on_threadpool::<req::CodeActionRequest>( |
87 | )?; | 108 | &mut req, pool, world, sender, handle_code_action, |
88 | handle_request_on_threadpool::<req::CodeActionRequest>( | 109 | )?; |
89 | &mut req, pool, world, sender, handle_code_action, | 110 | // dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |(), resp| { |
90 | )?; | 111 | // let world = world.snapshot(); |
112 | // let sender = sender.clone(); | ||
113 | // pool.execute(move || { | ||
114 | // let task = match handle_execute_command(world, params) { | ||
115 | // Ok(req) => Task::Request(req), | ||
116 | // Err(e) => Task::Die(e), | ||
117 | // }; | ||
118 | // sender.send(task) | ||
119 | // }); | ||
120 | // | ||
121 | // let resp = resp.into_response(Ok(()))?; | ||
122 | // io.send(RawMsg::Response(resp)); | ||
123 | // shutdown = true; | ||
124 | // Ok(()) | ||
125 | // })?; | ||
91 | 126 | ||
92 | let mut shutdown = false; | 127 | let mut shutdown = false; |
93 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { | 128 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { |
94 | let resp = resp.into_response(Ok(()))?; | 129 | let resp = resp.into_response(Ok(()))?; |
95 | io.send(RawMsg::Response(resp)); | 130 | io.send(RawMsg::Response(resp)); |
96 | shutdown = true; | 131 | shutdown = true; |
97 | Ok(()) | 132 | Ok(()) |
98 | })?; | 133 | })?; |
99 | if shutdown { | 134 | if shutdown { |
100 | info!("lifecycle: initiating shutdown"); | 135 | info!("lifecycle: initiating shutdown"); |
101 | return Ok(false); | 136 | return Ok(false); |
102 | } | 137 | } |
103 | if let Some(req) = req { | 138 | if let Some(req) = req { |
104 | error!("unknown method: {:?}", req); | 139 | error!("unknown method: {:?}", req); |
105 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); | 140 | io.send(RawMsg::Response(dispatch::unknown_method(req.id)?)); |
106 | } | 141 | } |
107 | } | ||
108 | RawMsg::Notification(not) => { | ||
109 | let mut not = Some(not); | ||
110 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | ||
111 | let path = params.text_document.file_path()?; | ||
112 | world.change_overlay(path, Some(params.text_document.text)); | ||
113 | update_file_notifications_on_threadpool( | ||
114 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | ||
115 | ); | ||
116 | Ok(()) | ||
117 | })?; | ||
118 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { | ||
119 | let path = params.text_document.file_path()?; | ||
120 | let text = params.content_changes.pop() | ||
121 | .ok_or_else(|| format_err!("empty changes"))? | ||
122 | .text; | ||
123 | world.change_overlay(path, Some(text)); | ||
124 | update_file_notifications_on_threadpool( | ||
125 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | ||
126 | ); | ||
127 | Ok(()) | ||
128 | })?; | ||
129 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | ||
130 | let path = params.text_document.file_path()?; | ||
131 | world.change_overlay(path, None); | ||
132 | let not = req::PublishDiagnosticsParams { | ||
133 | uri: params.text_document.uri, | ||
134 | diagnostics: Vec::new(), | ||
135 | }; | ||
136 | let not = dispatch::send_notification::<req::PublishDiagnostics>(not); | ||
137 | io.send(RawMsg::Notification(not)); | ||
138 | Ok(()) | ||
139 | })?; | ||
140 | |||
141 | if let Some(not) = not { | ||
142 | error!("unhandled notification: {:?}", not) | ||
143 | } | ||
144 | } | ||
145 | msg => { | ||
146 | eprintln!("msg = {:?}", msg); | ||
147 | } | ||
148 | }; | ||
149 | Ok(true) | 142 | Ok(true) |
150 | } | 143 | } |
151 | 144 | ||
145 | fn on_notification( | ||
146 | io: &mut Io, | ||
147 | world: &mut WorldState, | ||
148 | pool: &ThreadPool, | ||
149 | sender: &Sender<Task>, | ||
150 | not: RawNotification, | ||
151 | ) -> Result<()> { | ||
152 | let mut not = Some(not); | ||
153 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | ||
154 | let path = params.text_document.file_path()?; | ||
155 | world.change_overlay(path, Some(params.text_document.text)); | ||
156 | update_file_notifications_on_threadpool( | ||
157 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | ||
158 | ); | ||
159 | Ok(()) | ||
160 | })?; | ||
161 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { | ||
162 | let path = params.text_document.file_path()?; | ||
163 | let text = params.content_changes.pop() | ||
164 | .ok_or_else(|| format_err!("empty changes"))? | ||
165 | .text; | ||
166 | world.change_overlay(path, Some(text)); | ||
167 | update_file_notifications_on_threadpool( | ||
168 | pool, world.snapshot(), sender.clone(), params.text_document.uri, | ||
169 | ); | ||
170 | Ok(()) | ||
171 | })?; | ||
172 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | ||
173 | let path = params.text_document.file_path()?; | ||
174 | world.change_overlay(path, None); | ||
175 | let not = req::PublishDiagnosticsParams { | ||
176 | uri: params.text_document.uri, | ||
177 | diagnostics: Vec::new(), | ||
178 | }; | ||
179 | let not = dispatch::send_notification::<req::PublishDiagnostics>(not); | ||
180 | io.send(RawMsg::Notification(not)); | ||
181 | Ok(()) | ||
182 | })?; | ||
183 | |||
184 | if let Some(not) = not { | ||
185 | error!("unhandled notification: {:?}", not); | ||
186 | } | ||
187 | Ok(()) | ||
188 | } | ||
189 | |||
152 | fn handle_request_on_threadpool<R: req::ClientRequest>( | 190 | fn handle_request_on_threadpool<R: req::ClientRequest>( |
153 | req: &mut Option<RawRequest>, | 191 | req: &mut Option<RawRequest>, |
154 | pool: &ThreadPool, | 192 | pool: &ThreadPool, |