aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/main_loop
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-12 18:56:11 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-12 18:56:11 +0000
commite56072bfa3e5af69a4c293a38de6e1350ada3573 (patch)
treec7093fca262cedfc1fce2ba7499330fbb343c702 /crates/ra_lsp_server/src/main_loop
parentee80a92ed4245f1b6e2b11127c8636b63930073d (diff)
parent5bf739c824c25867811163e05f706ff3d20bd2e6 (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/src/main_loop')
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs141
1 files changed, 46 insertions, 95 deletions
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
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, 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;
17use std::io::Write; 17use std::io::Write;
18 18
19use crate::{ 19use 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
389pub fn handle_decorations( 296pub 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
579pub 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
672pub fn handle_document_highlight( 623pub fn handle_document_highlight(
673 world: ServerWorld, 624 world: ServerWorld,
674 params: req::TextDocumentPositionParams, 625 params: req::TextDocumentPositionParams,