diff options
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 142 |
1 files changed, 138 insertions, 4 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 | } |