diff options
author | Aleksey Kladov <[email protected]> | 2018-08-10 21:30:11 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-10 21:30:11 +0100 |
commit | 36d922c87d0c933803441bde825ace5658af78b2 (patch) | |
tree | 3c14a27b678cc01a02c04be04784b21b4366e964 | |
parent | 5896cd51de65cb6f7b8f3a4df85c4eb8886b76e2 (diff) |
diagnostics
-rw-r--r-- | crates/server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/server/src/dispatch.rs | 12 | ||||
-rw-r--r-- | crates/server/src/handlers.rs | 21 | ||||
-rw-r--r-- | crates/server/src/main.rs | 53 | ||||
-rw-r--r-- | crates/server/src/req.rs | 2 |
5 files changed, 81 insertions, 9 deletions
diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index e6d1b18c3..b2a7ce5b4 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml | |||
@@ -14,5 +14,7 @@ crossbeam-channel = "0.2.4" | |||
14 | threadpool = "1.7.1" | 14 | threadpool = "1.7.1" |
15 | flexi_logger = "0.9.0" | 15 | flexi_logger = "0.9.0" |
16 | log = "0.4.3" | 16 | log = "0.4.3" |
17 | url = "1.1.0" | ||
18 | |||
17 | libeditor = { path = "../libeditor" } | 19 | libeditor = { path = "../libeditor" } |
18 | libanalysis = { path = "../libanalysis" } | 20 | libanalysis = { path = "../libanalysis" } |
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs index 2da0996e3..d9681db40 100644 --- a/crates/server/src/dispatch.rs +++ b/crates/server/src/dispatch.rs | |||
@@ -136,6 +136,18 @@ pub fn handle_notification<N, F>(not: &mut Option<RawNotification>, f: F) -> Res | |||
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | pub fn send_notification<N>(io: &mut Io, params: N::Params) -> Result<()> | ||
140 | where | ||
141 | N: Notification, | ||
142 | N::Params: Serialize | ||
143 | { | ||
144 | io.send(RawMsg::Notification(RawNotification { | ||
145 | method: N::METHOD.to_string(), | ||
146 | params: serde_json::to_value(params)?, | ||
147 | })); | ||
148 | Ok(()) | ||
149 | } | ||
150 | |||
139 | 151 | ||
140 | pub fn unknown_method(io: &mut Io, raw: RawRequest) -> Result<()> { | 152 | pub fn unknown_method(io: &mut Io, raw: RawRequest) -> Result<()> { |
141 | error(io, raw.id, ErrorCode::MethodNotFound, "unknown method") | 153 | error(io, raw.id, ErrorCode::MethodNotFound, "unknown method") |
diff --git a/crates/server/src/handlers.rs b/crates/server/src/handlers.rs index 5ee87a4dd..1f55e8669 100644 --- a/crates/server/src/handlers.rs +++ b/crates/server/src/handlers.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | use languageserver_types::{Range, Position}; | 1 | use url::Url; |
2 | use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity}; | ||
2 | use libanalysis::World; | 3 | use libanalysis::World; |
3 | use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit}; | 4 | use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit}; |
5 | |||
4 | use {req, Result, FilePath}; | 6 | use {req, Result, FilePath}; |
5 | 7 | ||
6 | pub fn handle_syntax_tree( | 8 | pub fn handle_syntax_tree( |
@@ -29,6 +31,23 @@ pub fn handle_extend_selection( | |||
29 | Ok(req::ExtendSelectionResult { selections }) | 31 | Ok(req::ExtendSelectionResult { selections }) |
30 | } | 32 | } |
31 | 33 | ||
34 | pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> { | ||
35 | let path = uri.file_path()?; | ||
36 | let file = world.file_syntax(&path)?; | ||
37 | let line_index = world.file_line_index(&path)?; | ||
38 | let diagnostics = libeditor::diagnostics(&file) | ||
39 | .into_iter() | ||
40 | .map(|d| Diagnostic { | ||
41 | range: to_vs_range(&line_index, d.range), | ||
42 | severity: Some(DiagnosticSeverity::Error), | ||
43 | code: None, | ||
44 | source: Some("libsyntax2".to_string()), | ||
45 | message: d.msg, | ||
46 | related_information: None, | ||
47 | }).collect(); | ||
48 | Ok(req::PublishDiagnosticsParams { uri, diagnostics }) | ||
49 | } | ||
50 | |||
32 | 51 | ||
33 | fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange { | 52 | fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange { |
34 | TextRange::from_to( | 53 | TextRange::from_to( |
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 2d8695d23..6018350e3 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs | |||
@@ -11,6 +11,7 @@ extern crate crossbeam_channel; | |||
11 | extern crate threadpool; | 11 | extern crate threadpool; |
12 | #[macro_use] | 12 | #[macro_use] |
13 | extern crate log; | 13 | extern crate log; |
14 | extern crate url; | ||
14 | extern crate flexi_logger; | 15 | extern crate flexi_logger; |
15 | extern crate libeditor; | 16 | extern crate libeditor; |
16 | extern crate libanalysis; | 17 | extern crate libanalysis; |
@@ -31,7 +32,7 @@ use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier, Te | |||
31 | 32 | ||
32 | use ::{ | 33 | use ::{ |
33 | io::{Io, RawMsg}, | 34 | io::{Io, RawMsg}, |
34 | handlers::{handle_syntax_tree, handle_extend_selection}, | 35 | handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics}, |
35 | }; | 36 | }; |
36 | 37 | ||
37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 38 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
@@ -209,6 +210,21 @@ fn main_loop( | |||
209 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { | 210 | dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| { |
210 | let path = params.text_document.file_path()?; | 211 | let path = params.text_document.file_path()?; |
211 | world.change_overlay(path, Some(params.text_document.text)); | 212 | world.change_overlay(path, Some(params.text_document.text)); |
213 | let world = world.snapshot(); | ||
214 | let sender = sender.clone(); | ||
215 | let uri = params.text_document.uri; | ||
216 | pool.execute(move || { | ||
217 | match publish_diagnostics(world, uri) { | ||
218 | Err(e) => { | ||
219 | error!("failed to compute diagnostics: {:?}", e) | ||
220 | } | ||
221 | Ok(params) => { | ||
222 | sender.send(Box::new(|io: &mut Io| { | ||
223 | dispatch::send_notification::<req::PublishDiagnostics>(io, params) | ||
224 | })) | ||
225 | } | ||
226 | } | ||
227 | }); | ||
212 | Ok(()) | 228 | Ok(()) |
213 | })?; | 229 | })?; |
214 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { | 230 | dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| { |
@@ -217,11 +233,30 @@ fn main_loop( | |||
217 | .ok_or_else(|| format_err!("empty changes"))? | 233 | .ok_or_else(|| format_err!("empty changes"))? |
218 | .text; | 234 | .text; |
219 | world.change_overlay(path, Some(text)); | 235 | world.change_overlay(path, Some(text)); |
236 | let world = world.snapshot(); | ||
237 | let sender = sender.clone(); | ||
238 | let uri = params.text_document.uri; | ||
239 | pool.execute(move || { | ||
240 | match publish_diagnostics(world, uri) { | ||
241 | Err(e) => { | ||
242 | error!("failed to compute diagnostics: {:?}", e) | ||
243 | } | ||
244 | Ok(params) => { | ||
245 | sender.send(Box::new(|io: &mut Io| { | ||
246 | dispatch::send_notification::<req::PublishDiagnostics>(io, params) | ||
247 | })) | ||
248 | } | ||
249 | } | ||
250 | }); | ||
220 | Ok(()) | 251 | Ok(()) |
221 | })?; | 252 | })?; |
222 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | 253 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { |
223 | let path = params.text_document.file_path()?; | 254 | let path = params.text_document.file_path()?; |
224 | world.change_overlay(path, None); | 255 | world.change_overlay(path, None); |
256 | dispatch::send_notification::<req::PublishDiagnostics>(io, req::PublishDiagnosticsParams { | ||
257 | uri: params.text_document.uri, | ||
258 | diagnostics: Vec::new(), | ||
259 | })?; | ||
225 | Ok(()) | 260 | Ok(()) |
226 | })?; | 261 | })?; |
227 | 262 | ||
@@ -252,21 +287,25 @@ trait FilePath { | |||
252 | 287 | ||
253 | impl FilePath for TextDocumentItem { | 288 | impl FilePath for TextDocumentItem { |
254 | fn file_path(&self) -> Result<PathBuf> { | 289 | fn file_path(&self) -> Result<PathBuf> { |
255 | self.uri.to_file_path() | 290 | self.uri.file_path() |
256 | .map_err(|()| format_err!("invalid uri: {}", self.uri)) | ||
257 | } | 291 | } |
258 | } | 292 | } |
259 | 293 | ||
260 | impl FilePath for VersionedTextDocumentIdentifier { | 294 | impl FilePath for VersionedTextDocumentIdentifier { |
261 | fn file_path(&self) -> Result<PathBuf> { | 295 | fn file_path(&self) -> Result<PathBuf> { |
262 | self.uri.to_file_path() | 296 | self.uri.file_path() |
263 | .map_err(|()| format_err!("invalid uri: {}", self.uri)) | ||
264 | } | 297 | } |
265 | } | 298 | } |
266 | 299 | ||
267 | impl FilePath for TextDocumentIdentifier { | 300 | impl FilePath for TextDocumentIdentifier { |
268 | fn file_path(&self) -> Result<PathBuf> { | 301 | fn file_path(&self) -> Result<PathBuf> { |
269 | self.uri.to_file_path() | 302 | self.uri.file_path() |
270 | .map_err(|()| format_err!("invalid uri: {}", self.uri)) | 303 | } |
304 | } | ||
305 | |||
306 | impl FilePath for ::url::Url { | ||
307 | fn file_path(&self) -> Result<PathBuf> { | ||
308 | self.to_file_path() | ||
309 | .map_err(|()| format_err!("invalid uri: {}", self)) | ||
271 | } | 310 | } |
272 | } | 311 | } |
diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs index 4e588159b..64e7ef4ae 100644 --- a/crates/server/src/req.rs +++ b/crates/server/src/req.rs | |||
@@ -2,7 +2,7 @@ use languageserver_types::{TextDocumentIdentifier, Range}; | |||
2 | 2 | ||
3 | pub use languageserver_types::{ | 3 | pub use languageserver_types::{ |
4 | request::*, notification::*, | 4 | request::*, notification::*, |
5 | InitializeResult, | 5 | InitializeResult, PublishDiagnosticsParams |
6 | }; | 6 | }; |
7 | 7 | ||
8 | pub enum SyntaxTree {} | 8 | pub enum SyntaxTree {} |