Skip to content

Commit 6e4fca5

Browse files
bors[bot]vsrs
andauthored
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 <vit@conrlab.com>
2 parents a5f427c + b7db9f0 commit 6e4fca5

File tree

6 files changed

+312
-68
lines changed

6 files changed

+312
-68
lines changed

crates/ra_ide/src/hover.rs

Lines changed: 138 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,43 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs
1414

1515
use crate::{
1616
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,
1819
};
20+
use test_utils::mark;
1921

2022
#[derive(Clone, Debug, PartialEq, Eq)]
2123
pub struct HoverConfig {
2224
pub implementations: bool,
25+
pub run: bool,
26+
pub debug: bool,
2327
}
2428

2529
impl Default for HoverConfig {
2630
fn default() -> Self {
27-
Self { implementations: true }
31+
Self { implementations: true, run: true, debug: true }
2832
}
2933
}
3034

3135
impl HoverConfig {
32-
pub const NO_ACTIONS: Self = Self { implementations: false };
36+
pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false };
3337

3438
pub fn any(&self) -> bool {
35-
self.implementations
39+
self.implementations || self.runnable()
3640
}
3741

3842
pub fn none(&self) -> bool {
3943
!self.any()
4044
}
45+
46+
pub fn runnable(&self) -> bool {
47+
self.run || self.debug
48+
}
4149
}
4250

4351
#[derive(Debug, Clone)]
4452
pub enum HoverAction {
53+
Runnable(Runnable),
4554
Implementaion(FilePosition),
4655
}
4756

@@ -125,6 +134,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
125134
res.push_action(action);
126135
}
127136

137+
if let Some(action) = runnable_action(&sema, name_kind, position.file_id) {
138+
res.push_action(action);
139+
}
140+
128141
return Some(RangeInfo::new(range, res));
129142
}
130143
}
@@ -175,6 +188,36 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
175188
}
176189
}
177190

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+
178221
fn hover_text(
179222
docs: Option<String>,
180223
desc: Option<String>,
@@ -292,6 +335,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
292335
#[cfg(test)]
293336
mod tests {
294337
use super::*;
338+
use insta::assert_debug_snapshot;
295339

296340
use ra_db::FileLoader;
297341
use ra_syntax::TextRange;
@@ -309,6 +353,7 @@ mod tests {
309353
fn assert_impl_action(action: &HoverAction, position: u32) {
310354
let offset = match action {
311355
HoverAction::Implementaion(pos) => pos.offset,
356+
it => panic!("Unexpected hover action: {:#?}", it),
312357
};
313358
assert_eq!(offset, position.into());
314359
}
@@ -1076,6 +1121,8 @@ fn func(foo: i32) { if true { <|>foo; }; }
10761121

10771122
#[test]
10781123
fn test_hover_macro_generated_struct_fn_doc_comment() {
1124+
mark::check!(hover_macro_generated_struct_fn_doc_comment);
1125+
10791126
check_hover_result(
10801127
r#"
10811128
//- /lib.rs
@@ -1102,6 +1149,8 @@ fn func(foo: i32) { if true { <|>foo; }; }
11021149

11031150
#[test]
11041151
fn test_hover_macro_generated_struct_fn_doc_attr() {
1152+
mark::check!(hover_macro_generated_struct_fn_doc_attr);
1153+
11051154
check_hover_result(
11061155
r#"
11071156
//- /lib.rs
@@ -1176,4 +1225,89 @@ fn func(foo: i32) { if true { <|>foo; }; }
11761225
);
11771226
assert_impl_action(&actions[0], 5);
11781227
}
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+
}
11791313
}

0 commit comments

Comments
 (0)