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/main_loop | |
parent | 738c958a044361dc84a0f27e57b40f66a5815990 (diff) |
Code lens support for running tests
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 202 |
1 files changed, 121 insertions, 81 deletions
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, |