diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-12 18:56:11 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-12 18:56:11 +0000 |
commit | e56072bfa3e5af69a4c293a38de6e1350ada3573 (patch) | |
tree | c7093fca262cedfc1fce2ba7499330fbb343c702 /crates/ra_lsp_server | |
parent | ee80a92ed4245f1b6e2b11127c8636b63930073d (diff) | |
parent | 5bf739c824c25867811163e05f706ff3d20bd2e6 (diff) |
Merge #500
500: Code lens support for running tests r=matklad a=kjeremy
Supports running individual and mod tests.
I feel like this kind of abuses the `Runnables` infrastructure but it works. Maybe later on down the line we should introduce a struct that is really just a tuple of binary, arguments, and environment and pass that back to the client instead. `run_single.ts` is just a paired down version of `runnables.ts` and there is duplication because I think run_single will probably change independent of runnables.
Co-authored-by: Jeremy A. Kolb <[email protected]>
Co-authored-by: Jeremy Kolb <[email protected]>
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 6 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/cargo_target_spec.rs | 100 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 141 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 4 |
6 files changed, 154 insertions, 99 deletions
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 2599a4ca6..be6a6ead6 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use languageserver_types::{ | 1 | use languageserver_types::{ |
2 | CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, | 2 | CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, | 3 | ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, |
4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, | 4 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
5 | TextDocumentSyncOptions, | 5 | TextDocumentSyncOptions, |
@@ -32,7 +32,9 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
32 | document_symbol_provider: Some(true), | 32 | document_symbol_provider: Some(true), |
33 | workspace_symbol_provider: Some(true), | 33 | workspace_symbol_provider: Some(true), |
34 | code_action_provider: Some(CodeActionProviderCapability::Simple(true)), | 34 | code_action_provider: Some(CodeActionProviderCapability::Simple(true)), |
35 | code_lens_provider: None, | 35 | code_lens_provider: Some(CodeLensOptions { |
36 | resolve_provider: None, | ||
37 | }), | ||
36 | document_formatting_provider: Some(true), | 38 | document_formatting_provider: Some(true), |
37 | document_range_formatting_provider: None, | 39 | document_range_formatting_provider: None, |
38 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { | 40 | document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { |
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs new file mode 100644 index 000000000..a66f14b82 --- /dev/null +++ b/crates/ra_lsp_server/src/cargo_target_spec.rs | |||
@@ -0,0 +1,100 @@ | |||
1 | use crate::{ | ||
2 | project_model::TargetKind, | ||
3 | server_world::ServerWorld, | ||
4 | Result | ||
5 | }; | ||
6 | |||
7 | use ra_ide_api::{FileId, RunnableKind}; | ||
8 | |||
9 | pub(crate) fn runnable_args( | ||
10 | world: &ServerWorld, | ||
11 | file_id: FileId, | ||
12 | kind: &RunnableKind, | ||
13 | ) -> Result<Vec<String>> { | ||
14 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
15 | let mut res = Vec::new(); | ||
16 | match kind { | ||
17 | RunnableKind::Test { name } => { | ||
18 | res.push("test".to_string()); | ||
19 | if let Some(spec) = spec { | ||
20 | spec.push_to(&mut res); | ||
21 | } | ||
22 | res.push("--".to_string()); | ||
23 | res.push(name.to_string()); | ||
24 | res.push("--nocapture".to_string()); | ||
25 | } | ||
26 | RunnableKind::TestMod { path } => { | ||
27 | res.push("test".to_string()); | ||
28 | if let Some(spec) = spec { | ||
29 | spec.push_to(&mut res); | ||
30 | } | ||
31 | res.push("--".to_string()); | ||
32 | res.push(path.to_string()); | ||
33 | res.push("--nocapture".to_string()); | ||
34 | } | ||
35 | RunnableKind::Bin => { | ||
36 | res.push("run".to_string()); | ||
37 | if let Some(spec) = spec { | ||
38 | spec.push_to(&mut res); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | Ok(res) | ||
43 | } | ||
44 | |||
45 | pub struct CargoTargetSpec { | ||
46 | pub package: String, | ||
47 | pub target: String, | ||
48 | pub target_kind: TargetKind, | ||
49 | } | ||
50 | |||
51 | impl CargoTargetSpec { | ||
52 | pub fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> { | ||
53 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { | ||
54 | Some(crate_id) => crate_id, | ||
55 | None => return Ok(None), | ||
56 | }; | ||
57 | let file_id = world.analysis().crate_root(crate_id)?; | ||
58 | let path = world | ||
59 | .vfs | ||
60 | .read() | ||
61 | .file2path(ra_vfs::VfsFile(file_id.0.into())); | ||
62 | let res = world.workspaces.iter().find_map(|ws| { | ||
63 | let tgt = ws.cargo.target_by_root(&path)?; | ||
64 | let res = CargoTargetSpec { | ||
65 | package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), | ||
66 | target: tgt.name(&ws.cargo).to_string(), | ||
67 | target_kind: tgt.kind(&ws.cargo), | ||
68 | }; | ||
69 | Some(res) | ||
70 | }); | ||
71 | Ok(res) | ||
72 | } | ||
73 | |||
74 | pub fn push_to(self, buf: &mut Vec<String>) { | ||
75 | buf.push("--package".to_string()); | ||
76 | buf.push(self.package); | ||
77 | match self.target_kind { | ||
78 | TargetKind::Bin => { | ||
79 | buf.push("--bin".to_string()); | ||
80 | buf.push(self.target); | ||
81 | } | ||
82 | TargetKind::Test => { | ||
83 | buf.push("--test".to_string()); | ||
84 | buf.push(self.target); | ||
85 | } | ||
86 | TargetKind::Bench => { | ||
87 | buf.push("--bench".to_string()); | ||
88 | buf.push(self.target); | ||
89 | } | ||
90 | TargetKind::Example => { | ||
91 | buf.push("--example".to_string()); | ||
92 | buf.push(self.target); | ||
93 | } | ||
94 | TargetKind::Lib => { | ||
95 | buf.push("--lib".to_string()); | ||
96 | } | ||
97 | TargetKind::Other => (), | ||
98 | } | ||
99 | } | ||
100 | } | ||
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 725b1258a..f93d4b37d 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | mod caps; | 1 | mod caps; |
2 | mod cargo_target_spec; | ||
2 | mod conv; | 3 | mod conv; |
3 | mod main_loop; | 4 | mod main_loop; |
4 | mod project_model; | 5 | mod project_model; |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 6b9f6a988..03c834dbc 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -300,6 +300,7 @@ fn on_request( | |||
300 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 300 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
301 | .on::<req::Completion>(handlers::handle_completion)? | 301 | .on::<req::Completion>(handlers::handle_completion)? |
302 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? | 302 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? |
303 | .on::<req::CodeLensRequest>(handlers::handle_code_lens)? | ||
303 | .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? | 304 | .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? |
304 | .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? | 305 | .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? |
305 | .on::<req::HoverRequest>(handlers::handle_hover)? | 306 | .on::<req::HoverRequest>(handlers::handle_hover)? |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 5ab13542c..a781df181 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -2,7 +2,7 @@ use std::collections::HashMap; | |||
2 | 2 | ||
3 | use gen_lsp_server::ErrorCode; | 3 | use gen_lsp_server::ErrorCode; |
4 | use languageserver_types::{ | 4 | use languageserver_types::{ |
5 | CodeActionResponse, Command, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, | 5 | CodeActionResponse, Command, CodeLens, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, |
6 | DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, | 6 | DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, |
7 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, | 7 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, |
8 | ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, | 8 | ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, |
@@ -17,8 +17,8 @@ use serde_json::to_value; | |||
17 | use std::io::Write; | 17 | use std::io::Write; |
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | cargo_target_spec::{CargoTargetSpec, runnable_args}, | ||
20 | conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, | 21 | conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, |
21 | project_model::TargetKind, | ||
22 | req::{self, Decoration}, | 22 | req::{self, Decoration}, |
23 | server_world::ServerWorld, | 23 | server_world::ServerWorld, |
24 | LspError, Result, | 24 | LspError, Result, |
@@ -291,99 +291,6 @@ pub fn handle_runnables( | |||
291 | env: FxHashMap::default(), | 291 | env: FxHashMap::default(), |
292 | }); | 292 | }); |
293 | return Ok(res); | 293 | return Ok(res); |
294 | |||
295 | fn runnable_args( | ||
296 | world: &ServerWorld, | ||
297 | file_id: FileId, | ||
298 | kind: &RunnableKind, | ||
299 | ) -> Result<Vec<String>> { | ||
300 | let spec = CargoTargetSpec::for_file(world, file_id)?; | ||
301 | let mut res = Vec::new(); | ||
302 | match kind { | ||
303 | RunnableKind::Test { name } => { | ||
304 | res.push("test".to_string()); | ||
305 | if let Some(spec) = spec { | ||
306 | spec.push_to(&mut res); | ||
307 | } | ||
308 | res.push("--".to_string()); | ||
309 | res.push(name.to_string()); | ||
310 | res.push("--nocapture".to_string()); | ||
311 | } | ||
312 | RunnableKind::TestMod { path } => { | ||
313 | res.push("test".to_string()); | ||
314 | if let Some(spec) = spec { | ||
315 | spec.push_to(&mut res); | ||
316 | } | ||
317 | res.push("--".to_string()); | ||
318 | res.push(path.to_string()); | ||
319 | res.push("--nocapture".to_string()); | ||
320 | } | ||
321 | RunnableKind::Bin => { | ||
322 | res.push("run".to_string()); | ||
323 | if let Some(spec) = spec { | ||
324 | spec.push_to(&mut res); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | Ok(res) | ||
329 | } | ||
330 | |||
331 | struct CargoTargetSpec { | ||
332 | package: String, | ||
333 | target: String, | ||
334 | target_kind: TargetKind, | ||
335 | } | ||
336 | |||
337 | impl CargoTargetSpec { | ||
338 | fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> { | ||
339 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { | ||
340 | Some(crate_id) => crate_id, | ||
341 | None => return Ok(None), | ||
342 | }; | ||
343 | let file_id = world.analysis().crate_root(crate_id)?; | ||
344 | let path = world | ||
345 | .vfs | ||
346 | .read() | ||
347 | .file2path(ra_vfs::VfsFile(file_id.0.into())); | ||
348 | let res = world.workspaces.iter().find_map(|ws| { | ||
349 | let tgt = ws.cargo.target_by_root(&path)?; | ||
350 | let res = CargoTargetSpec { | ||
351 | package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), | ||
352 | target: tgt.name(&ws.cargo).to_string(), | ||
353 | target_kind: tgt.kind(&ws.cargo), | ||
354 | }; | ||
355 | Some(res) | ||
356 | }); | ||
357 | Ok(res) | ||
358 | } | ||
359 | |||
360 | fn push_to(self, buf: &mut Vec<String>) { | ||
361 | buf.push("--package".to_string()); | ||
362 | buf.push(self.package); | ||
363 | match self.target_kind { | ||
364 | TargetKind::Bin => { | ||
365 | buf.push("--bin".to_string()); | ||
366 | buf.push(self.target); | ||
367 | } | ||
368 | TargetKind::Test => { | ||
369 | buf.push("--test".to_string()); | ||
370 | buf.push(self.target); | ||
371 | } | ||
372 | TargetKind::Bench => { | ||
373 | buf.push("--bench".to_string()); | ||
374 | buf.push(self.target); | ||
375 | } | ||
376 | TargetKind::Example => { | ||
377 | buf.push("--example".to_string()); | ||
378 | buf.push(self.target); | ||
379 | } | ||
380 | TargetKind::Lib => { | ||
381 | buf.push("--lib".to_string()); | ||
382 | } | ||
383 | TargetKind::Other => (), | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | 294 | } |
388 | 295 | ||
389 | pub fn handle_decorations( | 296 | pub fn handle_decorations( |
@@ -669,6 +576,50 @@ pub fn handle_code_action( | |||
669 | Ok(Some(CodeActionResponse::Commands(res))) | 576 | Ok(Some(CodeActionResponse::Commands(res))) |
670 | } | 577 | } |
671 | 578 | ||
579 | pub fn handle_code_lens( | ||
580 | world: ServerWorld, | ||
581 | params: req::CodeLensParams, | ||
582 | ) -> Result<Option<Vec<CodeLens>>> { | ||
583 | let file_id = params.text_document.try_conv_with(&world)?; | ||
584 | let line_index = world.analysis().file_line_index(file_id); | ||
585 | |||
586 | let mut lenses: Vec<CodeLens> = Default::default(); | ||
587 | |||
588 | for runnable in world.analysis().runnables(file_id)? { | ||
589 | match &runnable.kind { | ||
590 | RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => { | ||
591 | let args = runnable_args(&world, file_id, &runnable.kind)?; | ||
592 | |||
593 | let range = runnable.range.conv_with(&line_index); | ||
594 | |||
595 | // This represents the actual command that will be run. | ||
596 | let r: req::Runnable = req::Runnable { | ||
597 | range, | ||
598 | label: Default::default(), | ||
599 | bin: "cargo".into(), | ||
600 | args, | ||
601 | env: Default::default(), | ||
602 | }; | ||
603 | |||
604 | let lens = CodeLens { | ||
605 | range, | ||
606 | command: Some(Command { | ||
607 | title: "Run Test".into(), | ||
608 | command: "ra-lsp.run-single".into(), | ||
609 | arguments: Some(vec![to_value(r).unwrap()]), | ||
610 | }), | ||
611 | data: None, | ||
612 | }; | ||
613 | |||
614 | lenses.push(lens); | ||
615 | } | ||
616 | _ => continue, | ||
617 | }; | ||
618 | } | ||
619 | |||
620 | return Ok(Some(lenses)); | ||
621 | } | ||
622 | |||
672 | pub fn handle_document_highlight( | 623 | pub fn handle_document_highlight( |
673 | world: ServerWorld, | 624 | world: ServerWorld, |
674 | params: req::TextDocumentPositionParams, | 625 | params: req::TextDocumentPositionParams, |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index b41e90328..c2b16725b 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; | |||
4 | use url_serde; | 4 | use url_serde; |
5 | 5 | ||
6 | pub use languageserver_types::{ | 6 | pub use languageserver_types::{ |
7 | notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams, | 7 | notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, CodeLensParams, |
8 | CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, | 8 | CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, |
9 | DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, | 9 | DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, |
10 | PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, | 10 | PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, |
11 | TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, | 11 | TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, |