aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
authorJeremy A. Kolb <[email protected]>2019-01-11 20:16:55 +0000
committerJeremy A. Kolb <[email protected]>2019-01-11 20:16:55 +0000
commitfaf003763516074c619cee7e43ca8bc365540c92 (patch)
tree54407f422a1a5b969b659f74fe4608be622ec596 /crates/ra_lsp_server
parent738c958a044361dc84a0f27e57b40f66a5815990 (diff)
Code lens support for running tests
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/src/caps.rs6
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs1
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs202
-rw-r--r--crates/ra_lsp_server/src/req.rs4
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 @@
1use languageserver_types::{ 1use 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
3use gen_lsp_server::ErrorCode; 3use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use 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( 296fn 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 { 328struct 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 { 334impl 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
665pub 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
669pub fn handle_document_highlight( 709pub 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};
4use url_serde; 4use url_serde;
5 5
6pub use languageserver_types::{ 6pub 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,