diff options
Diffstat (limited to 'codeless/server/src/main.rs')
-rw-r--r-- | codeless/server/src/main.rs | 126 |
1 files changed, 112 insertions, 14 deletions
diff --git a/codeless/server/src/main.rs b/codeless/server/src/main.rs index 11b6b7067..92f6a400c 100644 --- a/codeless/server/src/main.rs +++ b/codeless/server/src/main.rs | |||
@@ -6,7 +6,12 @@ extern crate serde; | |||
6 | extern crate serde_json; | 6 | extern crate serde_json; |
7 | extern crate languageserver_types; | 7 | extern crate languageserver_types; |
8 | extern crate drop_bomb; | 8 | extern crate drop_bomb; |
9 | #[macro_use] | ||
9 | extern crate crossbeam_channel; | 10 | extern crate crossbeam_channel; |
11 | extern crate threadpool; | ||
12 | #[macro_use] | ||
13 | extern crate log; | ||
14 | extern crate flexi_logger; | ||
10 | extern crate libeditor; | 15 | extern crate libeditor; |
11 | extern crate libanalysis; | 16 | extern crate libanalysis; |
12 | 17 | ||
@@ -16,16 +21,50 @@ mod req; | |||
16 | mod dispatch; | 21 | mod dispatch; |
17 | 22 | ||
18 | use languageserver_types::InitializeResult; | 23 | use languageserver_types::InitializeResult; |
24 | use threadpool::ThreadPool; | ||
25 | use crossbeam_channel::{bounded, Sender, Receiver}; | ||
26 | use flexi_logger::Logger; | ||
19 | use libanalysis::WorldState; | 27 | use libanalysis::WorldState; |
20 | use self::io::{Io, RawMsg}; | 28 | |
29 | use ::{ | ||
30 | io::{Io, RawMsg}, | ||
31 | }; | ||
21 | 32 | ||
22 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 33 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
23 | 34 | ||
24 | fn main() -> Result<()> { | 35 | fn main() -> Result<()> { |
36 | Logger::with_env_or_str("m=trace") | ||
37 | .log_to_file() | ||
38 | .directory("log") | ||
39 | .start()?; | ||
40 | info!("starting server"); | ||
41 | match ::std::panic::catch_unwind(|| main_inner()) { | ||
42 | Ok(res) => { | ||
43 | info!("shutting down: {:?}", res); | ||
44 | res | ||
45 | } | ||
46 | Err(_) => { | ||
47 | error!("server panicked"); | ||
48 | bail!("server panicked") | ||
49 | }, | ||
50 | } | ||
51 | } | ||
52 | |||
53 | fn main_inner() -> Result<()> { | ||
25 | let mut io = Io::from_stdio(); | 54 | let mut io = Io::from_stdio(); |
26 | initialize(&mut io)?; | 55 | let res = initialize(&mut io); |
27 | io.stop()?; | 56 | info!("shutting down IO..."); |
28 | Ok(()) | 57 | let io_res = io.stop(); |
58 | info!("... IO is down"); | ||
59 | match (res, io_res) { | ||
60 | (Ok(()), Ok(())) => Ok(()), | ||
61 | (res, Ok(())) => res, | ||
62 | (Ok(()), io_res) => io_res, | ||
63 | (res, Err(io_err)) => { | ||
64 | error!("shutdown error: {:?}", io_err); | ||
65 | res | ||
66 | } | ||
67 | } | ||
29 | } | 68 | } |
30 | 69 | ||
31 | fn initialize(io: &mut Io) -> Result<()> { | 70 | fn initialize(io: &mut Io) -> Result<()> { |
@@ -59,20 +98,69 @@ fn initialize(io: &mut Io) -> Result<()> { | |||
59 | } | 98 | } |
60 | } | 99 | } |
61 | 100 | ||
101 | type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>; | ||
102 | |||
62 | fn initialized(io: &mut Io) -> Result<()> { | 103 | fn initialized(io: &mut Io) -> Result<()> { |
63 | eprintln!("initialized"); | 104 | let mut world = WorldState::new(); |
64 | let world = WorldState::new(); | 105 | let mut pool = ThreadPool::new(4); |
106 | let (sender, receiver) = bounded::<Thunk>(16); | ||
107 | let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone()); | ||
108 | info!("waiting for background jobs to finish..."); | ||
109 | receiver.for_each(drop); | ||
110 | info!("...background jobs have finished"); | ||
111 | res | ||
112 | } | ||
113 | |||
114 | fn main_loop( | ||
115 | io: &mut Io, | ||
116 | world: &mut WorldState, | ||
117 | pool: &mut ThreadPool, | ||
118 | sender: Sender<Thunk>, | ||
119 | receiver: Receiver<Thunk>, | ||
120 | ) -> Result<()> { | ||
121 | info!("server initialized, serving requests"); | ||
65 | loop { | 122 | loop { |
66 | match io.recv()? { | 123 | enum Event { |
124 | Msg(RawMsg), | ||
125 | Thunk(Thunk), | ||
126 | ReceiverDead, | ||
127 | } | ||
128 | |||
129 | let event = select! { | ||
130 | recv(io.receiver(), msg) => match msg { | ||
131 | Some(msg) => Event::Msg(msg), | ||
132 | None => Event::ReceiverDead, | ||
133 | }, | ||
134 | recv(receiver, thunk) => Event::Thunk(thunk.unwrap()), | ||
135 | }; | ||
136 | |||
137 | let msg = match event { | ||
138 | Event::ReceiverDead => { | ||
139 | io.cleanup_receiver()?; | ||
140 | unreachable!(); | ||
141 | } | ||
142 | Event::Thunk(thunk) => { | ||
143 | thunk.call_box(io)?; | ||
144 | continue; | ||
145 | } | ||
146 | Event::Msg(msg) => msg, | ||
147 | }; | ||
148 | |||
149 | match msg { | ||
67 | RawMsg::Request(req) => { | 150 | RawMsg::Request(req) => { |
68 | let world = world.snapshot(); | ||
69 | if let Some((params, resp)) = dispatch::expect::<req::SyntaxTree>(io, req)? { | 151 | if let Some((params, resp)) = dispatch::expect::<req::SyntaxTree>(io, req)? { |
70 | resp.respond_with(io, || { | 152 | let world = world.snapshot(); |
71 | let path = params.text_document.uri.to_file_path() | 153 | let sender = sender.clone(); |
72 | .map_err(|()| format_err!("invalid path"))?; | 154 | pool.execute(move || { |
73 | let file = world.file_syntax(&path)?; | 155 | let res: Result<String> = (|| { |
74 | Ok(libeditor::syntax_tree(&file)) | 156 | let path = params.text_document.uri.to_file_path() |
75 | })? | 157 | .map_err(|()| format_err!("invalid path"))?; |
158 | let file = world.file_syntax(&path)?; | ||
159 | Ok(libeditor::syntax_tree(&file)) | ||
160 | })(); | ||
161 | |||
162 | sender.send(Box::new(|io: &mut Io| resp.response(io, res))) | ||
163 | }); | ||
76 | } | 164 | } |
77 | } | 165 | } |
78 | msg => { | 166 | msg => { |
@@ -82,3 +170,13 @@ fn initialized(io: &mut Io) -> Result<()> { | |||
82 | } | 170 | } |
83 | } | 171 | } |
84 | 172 | ||
173 | |||
174 | trait FnBox<A, R>: Send { | ||
175 | fn call_box(self: Box<Self>, a: A) -> R; | ||
176 | } | ||
177 | |||
178 | impl<A, R, F: FnOnce(A) -> R + Send> FnBox<A, R> for F { | ||
179 | fn call_box(self: Box<F>, a: A) -> R { | ||
180 | (*self)(a) | ||
181 | } | ||
182 | } | ||