@@ -14,34 +14,43 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs
1414
1515use 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 ) ]
2123pub struct HoverConfig {
2224 pub implementations : bool ,
25+ pub run : bool ,
26+ pub debug : bool ,
2327}
2428
2529impl Default for HoverConfig {
2630 fn default ( ) -> Self {
27- Self { implementations : true }
31+ Self { implementations : true , run : true , debug : true }
2832 }
2933}
3034
3135impl 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 ) ]
4452pub 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+
178221fn 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) ]
293336mod 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