@@ -14,34 +14,43 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs
14
14
15
15
use crate :: {
16
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
22
#[ derive( Clone , Debug , PartialEq , Eq ) ]
21
23
pub struct HoverConfig {
22
24
pub implementations : bool ,
25
+ pub run : bool ,
26
+ pub debug : bool ,
23
27
}
24
28
25
29
impl Default for HoverConfig {
26
30
fn default ( ) -> Self {
27
- Self { implementations : true }
31
+ Self { implementations : true , run : true , debug : true }
28
32
}
29
33
}
30
34
31
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
38
pub fn any ( & self ) -> bool {
35
- self . implementations
39
+ self . implementations || self . runnable ( )
36
40
}
37
41
38
42
pub fn none ( & self ) -> bool {
39
43
!self . any ( )
40
44
}
45
+
46
+ pub fn runnable ( & self ) -> bool {
47
+ self . run || self . debug
48
+ }
41
49
}
42
50
43
51
#[ derive( Debug , Clone ) ]
44
52
pub enum HoverAction {
53
+ Runnable ( Runnable ) ,
45
54
Implementaion ( FilePosition ) ,
46
55
}
47
56
@@ -125,6 +134,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
125
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
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
221
fn hover_text (
179
222
docs : Option < String > ,
180
223
desc : Option < String > ,
@@ -292,6 +335,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
292
335
#[ cfg( test) ]
293
336
mod tests {
294
337
use super :: * ;
338
+ use insta:: assert_debug_snapshot;
295
339
296
340
use ra_db:: FileLoader ;
297
341
use ra_syntax:: TextRange ;
@@ -309,6 +353,7 @@ mod tests {
309
353
fn assert_impl_action ( action : & HoverAction , position : u32 ) {
310
354
let offset = match action {
311
355
HoverAction :: Implementaion ( pos) => pos. offset ,
356
+ it => panic ! ( "Unexpected hover action: {:#?}" , it) ,
312
357
} ;
313
358
assert_eq ! ( offset, position. into( ) ) ;
314
359
}
@@ -1076,6 +1121,8 @@ fn func(foo: i32) { if true { <|>foo; }; }
1076
1121
1077
1122
#[ test]
1078
1123
fn test_hover_macro_generated_struct_fn_doc_comment ( ) {
1124
+ mark:: check!( hover_macro_generated_struct_fn_doc_comment) ;
1125
+
1079
1126
check_hover_result (
1080
1127
r#"
1081
1128
//- /lib.rs
@@ -1102,6 +1149,8 @@ fn func(foo: i32) { if true { <|>foo; }; }
1102
1149
1103
1150
#[ test]
1104
1151
fn test_hover_macro_generated_struct_fn_doc_attr ( ) {
1152
+ mark:: check!( hover_macro_generated_struct_fn_doc_attr) ;
1153
+
1105
1154
check_hover_result (
1106
1155
r#"
1107
1156
//- /lib.rs
@@ -1176,4 +1225,89 @@ fn func(foo: i32) { if true { <|>foo; }; }
1176
1225
) ;
1177
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
}
0 commit comments