aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/server/src/main.rs3
-rw-r--r--crates/server/src/main_loop/mod.rs196
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;
31use libanalysis::WorldState; 31use libanalysis::WorldState;
32 32
33use ::{ 33use ::{
34 io::{Io, RawMsg, RawResponse, RawNotification} 34 io::{Io, RawMsg, RawResponse, RawRequest, RawNotification}
35}; 35};
36 36
37pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 37pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
@@ -104,6 +104,7 @@ fn initialize(io: &mut Io) -> Result<()> {
104 104
105enum Task { 105enum 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 @@
1mod handlers; 1mod handlers;
2 2
3use std::collections::HashSet;
4
3use threadpool::ThreadPool; 5use threadpool::ThreadPool;
4use crossbeam_channel::{Sender, Receiver}; 6use crossbeam_channel::{Sender, Receiver};
5use languageserver_types::Url; 7use languageserver_types::Url;
6use libanalysis::{World, WorldState}; 8use libanalysis::{World, WorldState};
9
7use { 10use {
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
69fn on_msg( 90fn 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
145fn 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
152fn handle_request_on_threadpool<R: req::ClientRequest>( 190fn handle_request_on_threadpool<R: req::ClientRequest>(
153 req: &mut Option<RawRequest>, 191 req: &mut Option<RawRequest>,
154 pool: &ThreadPool, 192 pool: &ThreadPool,