From faf003763516074c619cee7e43ca8bc365540c92 Mon Sep 17 00:00:00 2001 From: "Jeremy A. Kolb" Date: Fri, 11 Jan 2019 15:16:55 -0500 Subject: Code lens support for running tests --- crates/ra_lsp_server/src/caps.rs | 6 +- crates/ra_lsp_server/src/main_loop.rs | 1 + crates/ra_lsp_server/src/main_loop/handlers.rs | 202 +++++++++++++++---------- crates/ra_lsp_server/src/req.rs | 4 +- 4 files changed, 128 insertions(+), 85 deletions(-) (limited to 'crates/ra_lsp_server') 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 @@ use languageserver_types::{ - CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, + CodeActionProviderCapability, CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, @@ -32,7 +32,9 @@ pub fn server_capabilities() -> ServerCapabilities { document_symbol_provider: Some(true), workspace_symbol_provider: Some(true), code_action_provider: Some(CodeActionProviderCapability::Simple(true)), - code_lens_provider: None, + code_lens_provider: Some(CodeLensOptions { + resolve_provider: None, + }), document_formatting_provider: Some(true), document_range_formatting_provider: None, 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( .on::(handlers::handle_decorations)? .on::(handlers::handle_completion)? .on::(handlers::handle_code_action)? + .on::(handlers::handle_code_lens)? .on::(handlers::handle_folding_range)? .on::(handlers::handle_signature_help)? .on::(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; use gen_lsp_server::ErrorCode; use languageserver_types::{ - CodeActionResponse, Command, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, + CodeActionResponse, Command, CodeLens, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkedString, MarkupContent, MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, @@ -291,97 +291,93 @@ pub fn handle_runnables( env: FxHashMap::default(), }); return Ok(res); +} - fn runnable_args( - world: &ServerWorld, - file_id: FileId, - kind: &RunnableKind, - ) -> Result> { - let spec = CargoTargetSpec::for_file(world, file_id)?; - let mut res = Vec::new(); - match kind { - RunnableKind::Test { name } => { - res.push("test".to_string()); - if let Some(spec) = spec { - spec.push_to(&mut res); - } - res.push("--".to_string()); - res.push(name.to_string()); - res.push("--nocapture".to_string()); +fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result> { + let spec = CargoTargetSpec::for_file(world, file_id)?; + let mut res = Vec::new(); + match kind { + RunnableKind::Test { name } => { + res.push("test".to_string()); + if let Some(spec) = spec { + spec.push_to(&mut res); } - RunnableKind::TestMod { path } => { - res.push("test".to_string()); - if let Some(spec) = spec { - spec.push_to(&mut res); - } - res.push("--".to_string()); - res.push(path.to_string()); - res.push("--nocapture".to_string()); + res.push("--".to_string()); + res.push(name.to_string()); + res.push("--nocapture".to_string()); + } + RunnableKind::TestMod { path } => { + res.push("test".to_string()); + if let Some(spec) = spec { + spec.push_to(&mut res); } - RunnableKind::Bin => { - res.push("run".to_string()); - if let Some(spec) = spec { - spec.push_to(&mut res); - } + res.push("--".to_string()); + res.push(path.to_string()); + res.push("--nocapture".to_string()); + } + RunnableKind::Bin => { + res.push("run".to_string()); + if let Some(spec) = spec { + spec.push_to(&mut res); } } - Ok(res) } + Ok(res) +} - struct CargoTargetSpec { - package: String, - target: String, - target_kind: TargetKind, - } +struct CargoTargetSpec { + package: String, + target: String, + target_kind: TargetKind, +} - impl CargoTargetSpec { - fn for_file(world: &ServerWorld, file_id: FileId) -> Result> { - let &crate_id = match world.analysis().crate_for(file_id)?.first() { - Some(crate_id) => crate_id, - None => return Ok(None), +impl CargoTargetSpec { + fn for_file(world: &ServerWorld, file_id: FileId) -> Result> { + let &crate_id = match world.analysis().crate_for(file_id)?.first() { + Some(crate_id) => crate_id, + None => return Ok(None), + }; + let file_id = world.analysis().crate_root(crate_id)?; + let path = world + .vfs + .read() + .file2path(ra_vfs::VfsFile(file_id.0.into())); + let res = world.workspaces.iter().find_map(|ws| { + let tgt = ws.cargo.target_by_root(&path)?; + let res = CargoTargetSpec { + package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), + target: tgt.name(&ws.cargo).to_string(), + target_kind: tgt.kind(&ws.cargo), }; - let file_id = world.analysis().crate_root(crate_id)?; - let path = world - .vfs - .read() - .file2path(ra_vfs::VfsFile(file_id.0.into())); - let res = world.workspaces.iter().find_map(|ws| { - let tgt = ws.cargo.target_by_root(&path)?; - let res = CargoTargetSpec { - package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), - target: tgt.name(&ws.cargo).to_string(), - target_kind: tgt.kind(&ws.cargo), - }; - Some(res) - }); - Ok(res) - } + Some(res) + }); + Ok(res) + } - fn push_to(self, buf: &mut Vec) { - buf.push("--package".to_string()); - buf.push(self.package); - match self.target_kind { - TargetKind::Bin => { - buf.push("--bin".to_string()); - buf.push(self.target); - } - TargetKind::Test => { - buf.push("--test".to_string()); - buf.push(self.target); - } - TargetKind::Bench => { - buf.push("--bench".to_string()); - buf.push(self.target); - } - TargetKind::Example => { - buf.push("--example".to_string()); - buf.push(self.target); - } - TargetKind::Lib => { - buf.push("--lib".to_string()); - } - TargetKind::Other => (), + fn push_to(self, buf: &mut Vec) { + buf.push("--package".to_string()); + buf.push(self.package); + match self.target_kind { + TargetKind::Bin => { + buf.push("--bin".to_string()); + buf.push(self.target); + } + TargetKind::Test => { + buf.push("--test".to_string()); + buf.push(self.target); + } + TargetKind::Bench => { + buf.push("--bench".to_string()); + buf.push(self.target); + } + TargetKind::Example => { + buf.push("--example".to_string()); + buf.push(self.target); + } + TargetKind::Lib => { + buf.push("--lib".to_string()); } + TargetKind::Other => (), } } } @@ -666,6 +662,50 @@ pub fn handle_code_action( Ok(Some(CodeActionResponse::Commands(res))) } +pub fn handle_code_lens( + world: ServerWorld, + params: req::CodeLensParams, +) -> Result>> { + let file_id = params.text_document.try_conv_with(&world)?; + let line_index = world.analysis().file_line_index(file_id); + + let mut lenses: Vec = Default::default(); + + for runnable in world.analysis().runnables(file_id)? { + match &runnable.kind { + RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => { + let args = runnable_args(&world, file_id, &runnable.kind)?; + + let range = runnable.range.conv_with(&line_index); + + // This represents the actual command that will be run. + let r: req::Runnable = req::Runnable { + range, + label: Default::default(), + bin: "cargo".into(), + args, + env: Default::default(), + }; + + let lens = CodeLens { + range, + command: Some(Command { + title: "Run Test".into(), + command: "ra-lsp.run-single".into(), + arguments: Some(vec![to_value(r).unwrap()]), + }), + data: None, + }; + + lenses.push(lens); + } + _ => continue, + }; + } + + return Ok(Some(lenses)); +} + pub fn handle_document_highlight( world: ServerWorld, 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}; use url_serde; pub use languageserver_types::{ - notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams, - CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, + notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, CodeLensParams, + CompletionParams, CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, -- cgit v1.2.3