diff options
author | Jeremy A. Kolb <[email protected]> | 2019-01-11 20:16:55 +0000 |
---|---|---|
committer | Jeremy A. Kolb <[email protected]> | 2019-01-11 20:16:55 +0000 |
commit | faf003763516074c619cee7e43ca8bc365540c92 (patch) | |
tree | 54407f422a1a5b969b659f74fe4608be622ec596 /crates/ra_lsp_server/src | |
parent | 738c958a044361dc84a0f27e57b40f66a5815990 (diff) |
Code lens support for running tests
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 6 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 202 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 4 |
4 files changed, 128 insertions, 85 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/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index c43637351..726c758aa 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 aad9d6568..f881bd703 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, MarkedString, MarkupContent, MarkupKind, | 7 | FoldingRangeParams, Hover, HoverContents, Location, MarkedString, MarkupContent, MarkupKind, |
8 | ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, | 8 | ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, |
@@ -291,97 +291,93 @@ pub fn handle_runnables( | |||
291 | env: FxHashMap::default(), | 291 | env: FxHashMap::default(), |
292 | }); | 292 | }); |
293 | return Ok(res); | 293 | return Ok(res); |
294 | } | ||
294 | 295 | ||
295 | fn runnable_args( | 296 | fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> { |
296 | world: &ServerWorld, | 297 | let spec = CargoTargetSpec::for_file(world, file_id)?; |
297 | file_id: FileId, | 298 | let mut res = Vec::new(); |
298 | kind: &RunnableKind, | 299 | match kind { |
299 | ) -> Result<Vec<String>> { | 300 | RunnableKind::Test { name } => { |
300 | let spec = CargoTargetSpec::for_file(world, file_id)?; | 301 | res.push("test".to_string()); |
301 | let mut res = Vec::new(); | 302 | if let Some(spec) = spec { |
302 | match kind { | 303 | spec.push_to(&mut res); |
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 | } | 304 | } |
312 | RunnableKind::TestMod { path } => { | 305 | res.push("--".to_string()); |
313 | res.push("test".to_string()); | 306 | res.push(name.to_string()); |
314 | if let Some(spec) = spec { | 307 | res.push("--nocapture".to_string()); |
315 | spec.push_to(&mut res); | 308 | } |
316 | } | 309 | RunnableKind::TestMod { path } => { |
317 | res.push("--".to_string()); | 310 | res.push("test".to_string()); |
318 | res.push(path.to_string()); | 311 | if let Some(spec) = spec { |
319 | res.push("--nocapture".to_string()); | 312 | spec.push_to(&mut res); |
320 | } | 313 | } |
321 | RunnableKind::Bin => { | 314 | res.push("--".to_string()); |
322 | res.push("run".to_string()); | 315 | res.push(path.to_string()); |
323 | if let Some(spec) = spec { | 316 | res.push("--nocapture".to_string()); |
324 | spec.push_to(&mut res); | 317 | } |
325 | } | 318 | RunnableKind::Bin => { |
319 | res.push("run".to_string()); | ||
320 | if let Some(spec) = spec { | ||
321 | spec.push_to(&mut res); | ||
326 | } | 322 | } |
327 | } | 323 | } |
328 | Ok(res) | ||
329 | } | 324 | } |
325 | Ok(res) | ||
326 | } | ||
330 | 327 | ||
331 | struct CargoTargetSpec { | 328 | struct CargoTargetSpec { |
332 | package: String, | 329 | package: String, |
333 | target: String, | 330 | target: String, |
334 | target_kind: TargetKind, | 331 | target_kind: TargetKind, |
335 | } | 332 | } |
336 | 333 | ||
337 | impl CargoTargetSpec { | 334 | impl CargoTargetSpec { |
338 | fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> { | 335 | fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> { |
339 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { | 336 | let &crate_id = match world.analysis().crate_for(file_id)?.first() { |
340 | Some(crate_id) => crate_id, | 337 | Some(crate_id) => crate_id, |
341 | None => return Ok(None), | 338 | None => return Ok(None), |
339 | }; | ||
340 | let file_id = world.analysis().crate_root(crate_id)?; | ||
341 | let path = world | ||
342 | .vfs | ||
343 | .read() | ||
344 | .file2path(ra_vfs::VfsFile(file_id.0.into())); | ||
345 | let res = world.workspaces.iter().find_map(|ws| { | ||
346 | let tgt = ws.cargo.target_by_root(&path)?; | ||
347 | let res = CargoTargetSpec { | ||
348 | package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), | ||
349 | target: tgt.name(&ws.cargo).to_string(), | ||
350 | target_kind: tgt.kind(&ws.cargo), | ||
342 | }; | 351 | }; |
343 | let file_id = world.analysis().crate_root(crate_id)?; | 352 | Some(res) |
344 | let path = world | 353 | }); |
345 | .vfs | 354 | Ok(res) |
346 | .read() | 355 | } |
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 | 356 | ||
360 | fn push_to(self, buf: &mut Vec<String>) { | 357 | fn push_to(self, buf: &mut Vec<String>) { |
361 | buf.push("--package".to_string()); | 358 | buf.push("--package".to_string()); |
362 | buf.push(self.package); | 359 | buf.push(self.package); |
363 | match self.target_kind { | 360 | match self.target_kind { |
364 | TargetKind::Bin => { | 361 | TargetKind::Bin => { |
365 | buf.push("--bin".to_string()); | 362 | buf.push("--bin".to_string()); |
366 | buf.push(self.target); | 363 | buf.push(self.target); |
367 | } | 364 | } |
368 | TargetKind::Test => { | 365 | TargetKind::Test => { |
369 | buf.push("--test".to_string()); | 366 | buf.push("--test".to_string()); |
370 | buf.push(self.target); | 367 | buf.push(self.target); |
371 | } | 368 | } |
372 | TargetKind::Bench => { | 369 | TargetKind::Bench => { |
373 | buf.push("--bench".to_string()); | 370 | buf.push("--bench".to_string()); |
374 | buf.push(self.target); | 371 | buf.push(self.target); |
375 | } | 372 | } |
376 | TargetKind::Example => { | 373 | TargetKind::Example => { |
377 | buf.push("--example".to_string()); | 374 | buf.push("--example".to_string()); |
378 | buf.push(self.target); | 375 | buf.push(self.target); |
379 | } | 376 | } |
380 | TargetKind::Lib => { | 377 | TargetKind::Lib => { |
381 | buf.push("--lib".to_string()); | 378 | buf.push("--lib".to_string()); |
382 | } | ||
383 | TargetKind::Other => (), | ||
384 | } | 379 | } |
380 | TargetKind::Other => (), | ||
385 | } | 381 | } |
386 | } | 382 | } |
387 | } | 383 | } |
@@ -666,6 +662,50 @@ pub fn handle_code_action( | |||
666 | Ok(Some(CodeActionResponse::Commands(res))) | 662 | Ok(Some(CodeActionResponse::Commands(res))) |
667 | } | 663 | } |
668 | 664 | ||
665 | pub fn handle_code_lens( | ||
666 | world: ServerWorld, | ||
667 | params: req::CodeLensParams, | ||
668 | ) -> Result<Option<Vec<CodeLens>>> { | ||
669 | let file_id = params.text_document.try_conv_with(&world)?; | ||
670 | let line_index = world.analysis().file_line_index(file_id); | ||
671 | |||
672 | let mut lenses: Vec<CodeLens> = Default::default(); | ||
673 | |||
674 | for runnable in world.analysis().runnables(file_id)? { | ||
675 | match &runnable.kind { | ||
676 | RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => { | ||
677 | let args = runnable_args(&world, file_id, &runnable.kind)?; | ||
678 | |||
679 | let range = runnable.range.conv_with(&line_index); | ||
680 | |||
681 | // This represents the actual command that will be run. | ||
682 | let r: req::Runnable = req::Runnable { | ||
683 | range, | ||
684 | label: Default::default(), | ||
685 | bin: "cargo".into(), | ||
686 | args, | ||
687 | env: Default::default(), | ||
688 | }; | ||
689 | |||
690 | let lens = CodeLens { | ||
691 | range, | ||
692 | command: Some(Command { | ||
693 | title: "Run Test".into(), | ||
694 | command: "ra-lsp.run-single".into(), | ||
695 | arguments: Some(vec![to_value(r).unwrap()]), | ||
696 | }), | ||
697 | data: None, | ||
698 | }; | ||
699 | |||
700 | lenses.push(lens); | ||
701 | } | ||
702 | _ => continue, | ||
703 | }; | ||
704 | } | ||
705 | |||
706 | return Ok(Some(lenses)); | ||
707 | } | ||
708 | |||
669 | pub fn handle_document_highlight( | 709 | pub fn handle_document_highlight( |
670 | world: ServerWorld, | 710 | world: ServerWorld, |
671 | params: req::TextDocumentPositionParams, | 711 | 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, |