aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/server/src/main_loop/mod.rs')
-rw-r--r--crates/server/src/main_loop/mod.rs108
1 files changed, 77 insertions, 31 deletions
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;
2mod subscriptions; 2mod subscriptions;
3 3
4use std::{ 4use std::{
5 collections::{HashSet}, 5 collections::{HashMap},
6}; 6};
7 7
8use threadpool::ThreadPool; 8use threadpool::ThreadPool;
9use crossbeam_channel::{Sender, Receiver}; 9use crossbeam_channel::{Sender, Receiver};
10use libanalysis::FileId; 10use languageserver_types::{NumberOrString};
11use libanalysis::{FileId, JobHandle, JobToken};
11 12
12use { 13use {
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(
109fn on_request( 112fn 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(
154fn on_notification( 166fn 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
197struct PoolDispatcher<'a> { 222struct 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
204impl<'a> PoolDispatcher<'a> { 230impl<'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
226fn update_file_notifications_on_threadpool( 272fn update_file_notifications_on_threadpool(