diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-06-08 12:29:35 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-08 12:29:35 +0100 |
commit | 6e4fca5882bdd6d00dfcc384473c1f612e00baa2 (patch) | |
tree | 07fd36fde432cc8d42d23408a67133422a94fedb | |
parent | a5f427ced3ee0ec27041f0b7632b4baae6a736b2 (diff) | |
parent | b7db9f058ad51b7ba47db02b581a76b6756d74e8 (diff) |
Merge #4773
4773: Run|Debug hover actions. r=matklad a=vsrs
![hover_actions_run](https://user-images.githubusercontent.com/62505555/83335644-dfc1f780-a2b6-11ea-820b-ccaa82290e7d.gif)
This hover actions work exactly like corresponding lenses.
Co-authored-by: vsrs <[email protected]>
-rw-r--r-- | crates/ra_ide/src/hover.rs | 142 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 92 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 122 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 12 | ||||
-rw-r--r-- | editors/code/package.json | 10 |
6 files changed, 312 insertions, 68 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 846d8c69b..ad78b7671 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -14,34 +14,43 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs | |||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, | 16 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, |
17 | FilePosition, NavigationTarget, RangeInfo, | 17 | runnables::runnable, |
18 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | ||
18 | }; | 19 | }; |
20 | use test_utils::mark; | ||
19 | 21 | ||
20 | #[derive(Clone, Debug, PartialEq, Eq)] | 22 | #[derive(Clone, Debug, PartialEq, Eq)] |
21 | pub struct HoverConfig { | 23 | pub struct HoverConfig { |
22 | pub implementations: bool, | 24 | pub implementations: bool, |
25 | pub run: bool, | ||
26 | pub debug: bool, | ||
23 | } | 27 | } |
24 | 28 | ||
25 | impl Default for HoverConfig { | 29 | impl Default for HoverConfig { |
26 | fn default() -> Self { | 30 | fn default() -> Self { |
27 | Self { implementations: true } | 31 | Self { implementations: true, run: true, debug: true } |
28 | } | 32 | } |
29 | } | 33 | } |
30 | 34 | ||
31 | impl HoverConfig { | 35 | impl HoverConfig { |
32 | pub const NO_ACTIONS: Self = Self { implementations: false }; | 36 | pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; |
33 | 37 | ||
34 | pub fn any(&self) -> bool { | 38 | pub fn any(&self) -> bool { |
35 | self.implementations | 39 | self.implementations || self.runnable() |
36 | } | 40 | } |
37 | 41 | ||
38 | pub fn none(&self) -> bool { | 42 | pub fn none(&self) -> bool { |
39 | !self.any() | 43 | !self.any() |
40 | } | 44 | } |
45 | |||
46 | pub fn runnable(&self) -> bool { | ||
47 | self.run || self.debug | ||
48 | } | ||
41 | } | 49 | } |
42 | 50 | ||
43 | #[derive(Debug, Clone)] | 51 | #[derive(Debug, Clone)] |
44 | pub enum HoverAction { | 52 | pub enum HoverAction { |
53 | Runnable(Runnable), | ||
45 | Implementaion(FilePosition), | 54 | Implementaion(FilePosition), |
46 | } | 55 | } |
47 | 56 | ||
@@ -125,6 +134,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
125 | res.push_action(action); | 134 | res.push_action(action); |
126 | } | 135 | } |
127 | 136 | ||
137 | if let Some(action) = runnable_action(&sema, name_kind, position.file_id) { | ||
138 | res.push_action(action); | ||
139 | } | ||
140 | |||
128 | return Some(RangeInfo::new(range, res)); | 141 | return Some(RangeInfo::new(range, res)); |
129 | } | 142 | } |
130 | } | 143 | } |
@@ -175,6 +188,36 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
175 | } | 188 | } |
176 | } | 189 | } |
177 | 190 | ||
191 | fn runnable_action( | ||
192 | sema: &Semantics<RootDatabase>, | ||
193 | def: Definition, | ||
194 | file_id: FileId, | ||
195 | ) -> Option<HoverAction> { | ||
196 | match def { | ||
197 | Definition::ModuleDef(it) => match it { | ||
198 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | ||
199 | ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) | ||
200 | .map(|it| HoverAction::Runnable(it)), | ||
201 | _ => None, | ||
202 | }, | ||
203 | ModuleDef::Function(it) => { | ||
204 | let src = it.source(sema.db); | ||
205 | if src.file_id != file_id.into() { | ||
206 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | ||
207 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | ||
208 | |||
209 | return None; | ||
210 | } | ||
211 | |||
212 | runnable(&sema, src.value.syntax().clone(), file_id) | ||
213 | .map(|it| HoverAction::Runnable(it)) | ||
214 | } | ||
215 | _ => None, | ||
216 | }, | ||
217 | _ => None, | ||
218 | } | ||
219 | } | ||
220 | |||
178 | fn hover_text( | 221 | fn hover_text( |
179 | docs: Option<String>, | 222 | docs: Option<String>, |
180 | desc: Option<String>, | 223 | desc: Option<String>, |
@@ -292,6 +335,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
292 | #[cfg(test)] | 335 | #[cfg(test)] |
293 | mod tests { | 336 | mod tests { |
294 | use super::*; | 337 | use super::*; |
338 | use insta::assert_debug_snapshot; | ||
295 | 339 | ||
296 | use ra_db::FileLoader; | 340 | use ra_db::FileLoader; |
297 | use ra_syntax::TextRange; | 341 | use ra_syntax::TextRange; |
@@ -309,6 +353,7 @@ mod tests { | |||
309 | fn assert_impl_action(action: &HoverAction, position: u32) { | 353 | fn assert_impl_action(action: &HoverAction, position: u32) { |
310 | let offset = match action { | 354 | let offset = match action { |
311 | HoverAction::Implementaion(pos) => pos.offset, | 355 | HoverAction::Implementaion(pos) => pos.offset, |
356 | it => panic!("Unexpected hover action: {:#?}", it), | ||
312 | }; | 357 | }; |
313 | assert_eq!(offset, position.into()); | 358 | assert_eq!(offset, position.into()); |
314 | } | 359 | } |
@@ -1076,6 +1121,8 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1076 | 1121 | ||
1077 | #[test] | 1122 | #[test] |
1078 | fn test_hover_macro_generated_struct_fn_doc_comment() { | 1123 | fn test_hover_macro_generated_struct_fn_doc_comment() { |
1124 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | ||
1125 | |||
1079 | check_hover_result( | 1126 | check_hover_result( |
1080 | r#" | 1127 | r#" |
1081 | //- /lib.rs | 1128 | //- /lib.rs |
@@ -1102,6 +1149,8 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1102 | 1149 | ||
1103 | #[test] | 1150 | #[test] |
1104 | fn test_hover_macro_generated_struct_fn_doc_attr() { | 1151 | fn test_hover_macro_generated_struct_fn_doc_attr() { |
1152 | mark::check!(hover_macro_generated_struct_fn_doc_attr); | ||
1153 | |||
1105 | check_hover_result( | 1154 | check_hover_result( |
1106 | r#" | 1155 | r#" |
1107 | //- /lib.rs | 1156 | //- /lib.rs |
@@ -1176,4 +1225,89 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
1176 | ); | 1225 | ); |
1177 | assert_impl_action(&actions[0], 5); | 1226 | assert_impl_action(&actions[0], 5); |
1178 | } | 1227 | } |
1228 | |||
1229 | #[test] | ||
1230 | fn test_hover_test_has_action() { | ||
1231 | let (_, actions) = check_hover_result( | ||
1232 | " | ||
1233 | //- /lib.rs | ||
1234 | #[test] | ||
1235 | fn foo_<|>test() {} | ||
1236 | ", | ||
1237 | &["fn foo_test()"], | ||
1238 | ); | ||
1239 | assert_debug_snapshot!(actions, | ||
1240 | @r###" | ||
1241 | [ | ||
1242 | Runnable( | ||
1243 | Runnable { | ||
1244 | nav: NavigationTarget { | ||
1245 | file_id: FileId( | ||
1246 | 1, | ||
1247 | ), | ||
1248 | full_range: 0..24, | ||
1249 | name: "foo_test", | ||
1250 | kind: FN_DEF, | ||
1251 | focus_range: Some( | ||
1252 | 11..19, | ||
1253 | ), | ||
1254 | container_name: None, | ||
1255 | description: None, | ||
1256 | docs: None, | ||
1257 | }, | ||
1258 | kind: Test { | ||
1259 | test_id: Path( | ||
1260 | "foo_test", | ||
1261 | ), | ||
1262 | attr: TestAttr { | ||
1263 | ignore: false, | ||
1264 | }, | ||
1265 | }, | ||
1266 | cfg_exprs: [], | ||
1267 | }, | ||
1268 | ), | ||
1269 | ] | ||
1270 | "###); | ||
1271 | } | ||
1272 | |||
1273 | #[test] | ||
1274 | fn test_hover_test_mod_has_action() { | ||
1275 | let (_, actions) = check_hover_result( | ||
1276 | " | ||
1277 | //- /lib.rs | ||
1278 | mod tests<|> { | ||
1279 | #[test] | ||
1280 | fn foo_test() {} | ||
1281 | } | ||
1282 | ", | ||
1283 | &["mod tests"], | ||
1284 | ); | ||
1285 | assert_debug_snapshot!(actions, | ||
1286 | @r###" | ||
1287 | [ | ||
1288 | Runnable( | ||
1289 | Runnable { | ||
1290 | nav: NavigationTarget { | ||
1291 | file_id: FileId( | ||
1292 | 1, | ||
1293 | ), | ||
1294 | full_range: 0..46, | ||
1295 | name: "tests", | ||
1296 | kind: MODULE, | ||
1297 | focus_range: Some( | ||
1298 | 4..9, | ||
1299 | ), | ||
1300 | container_name: None, | ||
1301 | description: None, | ||
1302 | docs: None, | ||
1303 | }, | ||
1304 | kind: TestMod { | ||
1305 | path: "tests", | ||
1306 | }, | ||
1307 | cfg_exprs: [], | ||
1308 | }, | ||
1309 | ), | ||
1310 | ] | ||
1311 | "###); | ||
1312 | } | ||
1179 | } | 1313 | } |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index f32ce0d22..fc57dc33d 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -11,14 +11,14 @@ use ra_syntax::{ | |||
11 | 11 | ||
12 | use crate::{display::ToNav, FileId, NavigationTarget}; | 12 | use crate::{display::ToNav, FileId, NavigationTarget}; |
13 | 13 | ||
14 | #[derive(Debug)] | 14 | #[derive(Debug, Clone)] |
15 | pub struct Runnable { | 15 | pub struct Runnable { |
16 | pub nav: NavigationTarget, | 16 | pub nav: NavigationTarget, |
17 | pub kind: RunnableKind, | 17 | pub kind: RunnableKind, |
18 | pub cfg_exprs: Vec<CfgExpr>, | 18 | pub cfg_exprs: Vec<CfgExpr>, |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug, Clone)] |
22 | pub enum TestId { | 22 | pub enum TestId { |
23 | Name(String), | 23 | Name(String), |
24 | Path(String), | 24 | Path(String), |
@@ -33,7 +33,7 @@ impl fmt::Display for TestId { | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | #[derive(Debug)] | 36 | #[derive(Debug, Clone)] |
37 | pub enum RunnableKind { | 37 | pub enum RunnableKind { |
38 | Test { test_id: TestId, attr: TestAttr }, | 38 | Test { test_id: TestId, attr: TestAttr }, |
39 | TestMod { path: String }, | 39 | TestMod { path: String }, |
@@ -42,6 +42,42 @@ pub enum RunnableKind { | |||
42 | Bin, | 42 | Bin, |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Debug, Eq, PartialEq)] | ||
46 | pub struct RunnableAction { | ||
47 | pub run_title: &'static str, | ||
48 | pub debugee: bool, | ||
49 | } | ||
50 | |||
51 | const TEST: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Test", debugee: true }; | ||
52 | const DOCTEST: RunnableAction = | ||
53 | RunnableAction { run_title: "▶\u{fe0e} Run Doctest", debugee: false }; | ||
54 | const BENCH: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run Bench", debugee: true }; | ||
55 | const BIN: RunnableAction = RunnableAction { run_title: "▶\u{fe0e} Run", debugee: true }; | ||
56 | |||
57 | impl Runnable { | ||
58 | // test package::module::testname | ||
59 | pub fn label(&self, target: Option<String>) -> String { | ||
60 | match &self.kind { | ||
61 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
62 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
63 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
64 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
65 | RunnableKind::Bin => { | ||
66 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | pub fn action(&self) -> &'static RunnableAction { | ||
72 | match &self.kind { | ||
73 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => &TEST, | ||
74 | RunnableKind::DocTest { .. } => &DOCTEST, | ||
75 | RunnableKind::Bench { .. } => &BENCH, | ||
76 | RunnableKind::Bin => &BIN, | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
45 | // Feature: Run | 81 | // Feature: Run |
46 | // | 82 | // |
47 | // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor | 83 | // Shows a popup suggesting to run a test/benchmark/binary **at the current cursor |
@@ -59,7 +95,11 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | |||
59 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() | 95 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() |
60 | } | 96 | } |
61 | 97 | ||
62 | fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode, file_id: FileId) -> Option<Runnable> { | 98 | pub(crate) fn runnable( |
99 | sema: &Semantics<RootDatabase>, | ||
100 | item: SyntaxNode, | ||
101 | file_id: FileId, | ||
102 | ) -> Option<Runnable> { | ||
63 | match_ast! { | 103 | match_ast! { |
64 | match item { | 104 | match item { |
65 | ast::FnDef(it) => runnable_fn(sema, it, file_id), | 105 | ast::FnDef(it) => runnable_fn(sema, it, file_id), |
@@ -135,7 +175,7 @@ fn runnable_fn( | |||
135 | Some(Runnable { nav, kind, cfg_exprs }) | 175 | Some(Runnable { nav, kind, cfg_exprs }) |
136 | } | 176 | } |
137 | 177 | ||
138 | #[derive(Debug)] | 178 | #[derive(Debug, Copy, Clone)] |
139 | pub struct TestAttr { | 179 | pub struct TestAttr { |
140 | pub ignore: bool, | 180 | pub ignore: bool, |
141 | } | 181 | } |
@@ -207,6 +247,15 @@ mod tests { | |||
207 | 247 | ||
208 | use crate::mock_analysis::analysis_and_position; | 248 | use crate::mock_analysis::analysis_and_position; |
209 | 249 | ||
250 | use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; | ||
251 | |||
252 | fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { | ||
253 | assert_eq!( | ||
254 | actions, | ||
255 | runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() | ||
256 | ); | ||
257 | } | ||
258 | |||
210 | #[test] | 259 | #[test] |
211 | fn test_runnables() { | 260 | fn test_runnables() { |
212 | let (analysis, pos) = analysis_and_position( | 261 | let (analysis, pos) = analysis_and_position( |
@@ -221,6 +270,9 @@ mod tests { | |||
221 | #[test] | 270 | #[test] |
222 | #[ignore] | 271 | #[ignore] |
223 | fn test_foo() {} | 272 | fn test_foo() {} |
273 | |||
274 | #[bench] | ||
275 | fn bench() {} | ||
224 | "#, | 276 | "#, |
225 | ); | 277 | ); |
226 | let runnables = analysis.runnables(pos.file_id).unwrap(); | 278 | let runnables = analysis.runnables(pos.file_id).unwrap(); |
@@ -295,9 +347,32 @@ mod tests { | |||
295 | }, | 347 | }, |
296 | cfg_exprs: [], | 348 | cfg_exprs: [], |
297 | }, | 349 | }, |
350 | Runnable { | ||
351 | nav: NavigationTarget { | ||
352 | file_id: FileId( | ||
353 | 1, | ||
354 | ), | ||
355 | full_range: 82..104, | ||
356 | name: "bench", | ||
357 | kind: FN_DEF, | ||
358 | focus_range: Some( | ||
359 | 94..99, | ||
360 | ), | ||
361 | container_name: None, | ||
362 | description: None, | ||
363 | docs: None, | ||
364 | }, | ||
365 | kind: Bench { | ||
366 | test_id: Path( | ||
367 | "bench", | ||
368 | ), | ||
369 | }, | ||
370 | cfg_exprs: [], | ||
371 | }, | ||
298 | ] | 372 | ] |
299 | "### | 373 | "### |
300 | ); | 374 | ); |
375 | assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]); | ||
301 | } | 376 | } |
302 | 377 | ||
303 | #[test] | 378 | #[test] |
@@ -361,6 +436,7 @@ mod tests { | |||
361 | ] | 436 | ] |
362 | "### | 437 | "### |
363 | ); | 438 | ); |
439 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
364 | } | 440 | } |
365 | 441 | ||
366 | #[test] | 442 | #[test] |
@@ -427,6 +503,7 @@ mod tests { | |||
427 | ] | 503 | ] |
428 | "### | 504 | "### |
429 | ); | 505 | ); |
506 | assert_actions(&runnables, &[&BIN, &DOCTEST]); | ||
430 | } | 507 | } |
431 | 508 | ||
432 | #[test] | 509 | #[test] |
@@ -493,6 +570,7 @@ mod tests { | |||
493 | ] | 570 | ] |
494 | "### | 571 | "### |
495 | ); | 572 | ); |
573 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
496 | } | 574 | } |
497 | 575 | ||
498 | #[test] | 576 | #[test] |
@@ -561,6 +639,7 @@ mod tests { | |||
561 | ] | 639 | ] |
562 | "### | 640 | "### |
563 | ); | 641 | ); |
642 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
564 | } | 643 | } |
565 | 644 | ||
566 | #[test] | 645 | #[test] |
@@ -631,6 +710,7 @@ mod tests { | |||
631 | ] | 710 | ] |
632 | "### | 711 | "### |
633 | ); | 712 | ); |
713 | assert_actions(&runnables, &[&TEST, &TEST]); | ||
634 | } | 714 | } |
635 | 715 | ||
636 | #[test] | 716 | #[test] |
@@ -681,6 +761,7 @@ mod tests { | |||
681 | ] | 761 | ] |
682 | "### | 762 | "### |
683 | ); | 763 | ); |
764 | assert_actions(&runnables, &[&TEST]); | ||
684 | } | 765 | } |
685 | 766 | ||
686 | #[test] | 767 | #[test] |
@@ -739,6 +820,7 @@ mod tests { | |||
739 | ] | 820 | ] |
740 | "### | 821 | "### |
741 | ); | 822 | ); |
823 | assert_actions(&runnables, &[&TEST]); | ||
742 | } | 824 | } |
743 | 825 | ||
744 | #[test] | 826 | #[test] |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8d6efdbe8..17671f89e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -285,6 +285,8 @@ impl Config { | |||
285 | set(value, "/hoverActions/enable", &mut use_hover_actions); | 285 | set(value, "/hoverActions/enable", &mut use_hover_actions); |
286 | if use_hover_actions { | 286 | if use_hover_actions { |
287 | set(value, "/hoverActions/implementations", &mut self.hover.implementations); | 287 | set(value, "/hoverActions/implementations", &mut self.hover.implementations); |
288 | set(value, "/hoverActions/run", &mut self.hover.run); | ||
289 | set(value, "/hoverActions/debug", &mut self.hover.debug); | ||
288 | } else { | 290 | } else { |
289 | self.hover = HoverConfig::NO_ACTIONS; | 291 | self.hover = HoverConfig::NO_ACTIONS; |
290 | } | 292 | } |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 3ff779702..a41adf8b0 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -18,8 +18,8 @@ use lsp_types::{ | |||
18 | TextDocumentIdentifier, Url, WorkspaceEdit, | 18 | TextDocumentIdentifier, Url, WorkspaceEdit, |
19 | }; | 19 | }; |
20 | use ra_ide::{ | 20 | use ra_ide::{ |
21 | FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, RunnableKind, SearchScope, | 21 | FileId, FilePosition, FileRange, HoverAction, Query, RangeInfo, Runnable, RunnableKind, |
22 | TextEdit, | 22 | SearchScope, TextEdit, |
23 | }; | 23 | }; |
24 | use ra_prof::profile; | 24 | use ra_prof::profile; |
25 | use ra_project_model::TargetKind; | 25 | use ra_project_model::TargetKind; |
@@ -404,15 +404,10 @@ pub fn handle_runnables( | |||
404 | continue; | 404 | continue; |
405 | } | 405 | } |
406 | } | 406 | } |
407 | // Do not suggest binary run on other target than binary | 407 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
408 | if let RunnableKind::Bin = runnable.kind { | 408 | continue; |
409 | if let Some(spec) = &cargo_spec { | ||
410 | match spec.target_kind { | ||
411 | TargetKind::Bin => {} | ||
412 | _ => continue, | ||
413 | } | ||
414 | } | ||
415 | } | 409 | } |
410 | |||
416 | res.push(to_proto::runnable(&snap, file_id, runnable)?); | 411 | res.push(to_proto::runnable(&snap, file_id, runnable)?); |
417 | } | 412 | } |
418 | 413 | ||
@@ -555,7 +550,7 @@ pub fn handle_hover( | |||
555 | }), | 550 | }), |
556 | range: Some(range), | 551 | range: Some(range), |
557 | }, | 552 | }, |
558 | actions: prepare_hover_actions(&snap, info.info.actions()), | 553 | actions: prepare_hover_actions(&snap, position.file_id, info.info.actions()), |
559 | }; | 554 | }; |
560 | 555 | ||
561 | Ok(Some(hover)) | 556 | Ok(Some(hover)) |
@@ -817,55 +812,25 @@ pub fn handle_code_lens( | |||
817 | if snap.config.lens.runnable() { | 812 | if snap.config.lens.runnable() { |
818 | // Gather runnables | 813 | // Gather runnables |
819 | for runnable in snap.analysis().runnables(file_id)? { | 814 | for runnable in snap.analysis().runnables(file_id)? { |
820 | let (run_title, debugee) = match &runnable.kind { | 815 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
821 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => { | 816 | continue; |
822 | ("▶\u{fe0e} Run Test", true) | 817 | } |
823 | } | ||
824 | RunnableKind::DocTest { .. } => { | ||
825 | // cargo does not support -no-run for doctests | ||
826 | ("▶\u{fe0e} Run Doctest", false) | ||
827 | } | ||
828 | RunnableKind::Bench { .. } => { | ||
829 | // Nothing wrong with bench debugging | ||
830 | ("Run Bench", true) | ||
831 | } | ||
832 | RunnableKind::Bin => { | ||
833 | // Do not suggest binary run on other target than binary | ||
834 | match &cargo_spec { | ||
835 | Some(spec) => match spec.target_kind { | ||
836 | TargetKind::Bin => ("Run", true), | ||
837 | _ => continue, | ||
838 | }, | ||
839 | None => continue, | ||
840 | } | ||
841 | } | ||
842 | }; | ||
843 | 818 | ||
819 | let action = runnable.action(); | ||
844 | let range = to_proto::range(&line_index, runnable.nav.range()); | 820 | let range = to_proto::range(&line_index, runnable.nav.range()); |
845 | let r = to_proto::runnable(&snap, file_id, runnable)?; | 821 | let r = to_proto::runnable(&snap, file_id, runnable)?; |
846 | if snap.config.lens.run { | 822 | if snap.config.lens.run { |
847 | let lens = CodeLens { | 823 | let lens = CodeLens { |
848 | range, | 824 | range, |
849 | command: Some(Command { | 825 | command: Some(run_single_command(&r, action.run_title)), |
850 | title: run_title.to_string(), | ||
851 | command: "rust-analyzer.runSingle".into(), | ||
852 | arguments: Some(vec![to_value(&r).unwrap()]), | ||
853 | }), | ||
854 | data: None, | 826 | data: None, |
855 | }; | 827 | }; |
856 | lenses.push(lens); | 828 | lenses.push(lens); |
857 | } | 829 | } |
858 | 830 | ||
859 | if debugee && snap.config.lens.debug { | 831 | if action.debugee && snap.config.lens.debug { |
860 | let debug_lens = CodeLens { | 832 | let debug_lens = |
861 | range, | 833 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; |
862 | command: Some(Command { | ||
863 | title: "Debug".into(), | ||
864 | command: "rust-analyzer.debugSingle".into(), | ||
865 | arguments: Some(vec![to_value(r).unwrap()]), | ||
866 | }), | ||
867 | data: None, | ||
868 | }; | ||
869 | lenses.push(debug_lens); | 834 | lenses.push(debug_lens); |
870 | } | 835 | } |
871 | } | 836 | } |
@@ -1169,6 +1134,22 @@ fn show_references_command( | |||
1169 | } | 1134 | } |
1170 | } | 1135 | } |
1171 | 1136 | ||
1137 | fn run_single_command(runnable: &lsp_ext::Runnable, title: &str) -> Command { | ||
1138 | Command { | ||
1139 | title: title.to_string(), | ||
1140 | command: "rust-analyzer.runSingle".into(), | ||
1141 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | fn debug_single_command(runnable: &lsp_ext::Runnable) -> Command { | ||
1146 | Command { | ||
1147 | title: "Debug".into(), | ||
1148 | command: "rust-analyzer.debugSingle".into(), | ||
1149 | arguments: Some(vec![to_value(runnable).unwrap()]), | ||
1150 | } | ||
1151 | } | ||
1152 | |||
1172 | fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { | 1153 | fn to_command_link(command: Command, tooltip: String) -> lsp_ext::CommandLink { |
1173 | lsp_ext::CommandLink { tooltip: Some(tooltip), command } | 1154 | lsp_ext::CommandLink { tooltip: Some(tooltip), command } |
1174 | } | 1155 | } |
@@ -1199,8 +1180,37 @@ fn show_impl_command_link( | |||
1199 | None | 1180 | None |
1200 | } | 1181 | } |
1201 | 1182 | ||
1183 | fn to_runnable_action( | ||
1184 | snap: &GlobalStateSnapshot, | ||
1185 | file_id: FileId, | ||
1186 | runnable: Runnable, | ||
1187 | ) -> Option<lsp_ext::CommandLinkGroup> { | ||
1188 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; | ||
1189 | if should_skip_target(&runnable, cargo_spec.as_ref()) { | ||
1190 | return None; | ||
1191 | } | ||
1192 | |||
1193 | let action: &'static _ = runnable.action(); | ||
1194 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { | ||
1195 | let mut group = lsp_ext::CommandLinkGroup::default(); | ||
1196 | |||
1197 | if snap.config.hover.run { | ||
1198 | let run_command = run_single_command(&r, action.run_title); | ||
1199 | group.commands.push(to_command_link(run_command, r.label.clone())); | ||
1200 | } | ||
1201 | |||
1202 | if snap.config.hover.debug { | ||
1203 | let dbg_command = debug_single_command(&r); | ||
1204 | group.commands.push(to_command_link(dbg_command, r.label)); | ||
1205 | } | ||
1206 | |||
1207 | group | ||
1208 | }) | ||
1209 | } | ||
1210 | |||
1202 | fn prepare_hover_actions( | 1211 | fn prepare_hover_actions( |
1203 | snap: &GlobalStateSnapshot, | 1212 | snap: &GlobalStateSnapshot, |
1213 | file_id: FileId, | ||
1204 | actions: &[HoverAction], | 1214 | actions: &[HoverAction], |
1205 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1215 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1206 | if snap.config.hover.none() || !snap.config.client_caps.hover_actions { | 1216 | if snap.config.hover.none() || !snap.config.client_caps.hover_actions { |
@@ -1211,6 +1221,20 @@ fn prepare_hover_actions( | |||
1211 | .iter() | 1221 | .iter() |
1212 | .filter_map(|it| match it { | 1222 | .filter_map(|it| match it { |
1213 | HoverAction::Implementaion(position) => show_impl_command_link(snap, position), | 1223 | HoverAction::Implementaion(position) => show_impl_command_link(snap, position), |
1224 | HoverAction::Runnable(r) => to_runnable_action(snap, file_id, r.clone()), | ||
1214 | }) | 1225 | }) |
1215 | .collect() | 1226 | .collect() |
1216 | } | 1227 | } |
1228 | |||
1229 | fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool { | ||
1230 | match runnable.kind { | ||
1231 | RunnableKind::Bin => { | ||
1232 | // Do not suggest binary run on other target than binary | ||
1233 | match &cargo_spec { | ||
1234 | Some(spec) => spec.target_kind != TargetKind::Bin, | ||
1235 | None => true, | ||
1236 | } | ||
1237 | } | ||
1238 | _ => false, | ||
1239 | } | ||
1240 | } | ||
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1da4d80ec..710df1fbd 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -4,7 +4,7 @@ use ra_ide::{ | |||
4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, | 4 | Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, |
5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, | 5 | FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, |
6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, | 6 | InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, |
7 | ResolvedAssist, Runnable, RunnableKind, Severity, SourceChange, SourceFileEdit, TextEdit, | 7 | ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, |
8 | }; | 8 | }; |
9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 9 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
10 | use ra_vfs::LineEndings; | 10 | use ra_vfs::LineEndings; |
@@ -662,15 +662,7 @@ pub(crate) fn runnable( | |||
662 | let target = spec.as_ref().map(|s| s.target.clone()); | 662 | let target = spec.as_ref().map(|s| s.target.clone()); |
663 | let (cargo_args, executable_args) = | 663 | let (cargo_args, executable_args) = |
664 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; | 664 | CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; |
665 | let label = match &runnable.kind { | 665 | let label = runnable.label(target); |
666 | RunnableKind::Test { test_id, .. } => format!("test {}", test_id), | ||
667 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
668 | RunnableKind::Bench { test_id } => format!("bench {}", test_id), | ||
669 | RunnableKind::DocTest { test_id, .. } => format!("doctest {}", test_id), | ||
670 | RunnableKind::Bin => { | ||
671 | target.map_or_else(|| "run binary".to_string(), |t| format!("run {}", t)) | ||
672 | } | ||
673 | }; | ||
674 | let location = location_link(snap, None, runnable.nav)?; | 666 | let location = location_link(snap, None, runnable.nav)?; |
675 | 667 | ||
676 | Ok(lsp_ext::Runnable { | 668 | Ok(lsp_ext::Runnable { |
diff --git a/editors/code/package.json b/editors/code/package.json index 859ab4477..779d7e1b8 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -486,6 +486,16 @@ | |||
486 | "type": "boolean", | 486 | "type": "boolean", |
487 | "default": true | 487 | "default": true |
488 | }, | 488 | }, |
489 | "rust-analyzer.hoverActions.run": { | ||
490 | "markdownDescription": "Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | ||
491 | "type": "boolean", | ||
492 | "default": true | ||
493 | }, | ||
494 | "rust-analyzer.hoverActions.debug": { | ||
495 | "markdownDescription": "Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | ||
496 | "type": "boolean", | ||
497 | "default": true | ||
498 | }, | ||
489 | "rust-analyzer.linkedProjects": { | 499 | "rust-analyzer.linkedProjects": { |
490 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format", | 500 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format", |
491 | "type": "array", | 501 | "type": "array", |