@@ -5,6 +5,7 @@ use hir::{
5
5
use ide_db:: {
6
6
base_db:: SourceDatabase ,
7
7
defs:: { Definition , NameClass , NameRefClass } ,
8
+ helpers:: FamousDefs ,
8
9
RootDatabase ,
9
10
} ;
10
11
use itertools:: Itertools ;
@@ -107,16 +108,14 @@ pub(crate) fn hover(
107
108
}
108
109
} ;
109
110
if let Some ( definition) = definition {
110
- if let Some ( markup) = hover_for_definition ( db, definition) {
111
- let markup = markup. as_str ( ) ;
112
- let markup = if !markdown {
113
- remove_markdown ( markup)
114
- } else if links_in_hover {
115
- rewrite_links ( db, markup, & definition)
116
- } else {
117
- remove_links ( markup)
118
- } ;
119
- res. markup = Markup :: from ( markup) ;
111
+ let famous_defs = match & definition {
112
+ Definition :: ModuleDef ( ModuleDef :: BuiltinType ( _) ) => {
113
+ Some ( FamousDefs ( & sema, sema. scope ( & node) . krate ( ) ) )
114
+ }
115
+ _ => None ,
116
+ } ;
117
+ if let Some ( markup) = hover_for_definition ( db, definition, famous_defs. as_ref ( ) ) {
118
+ res. markup = process_markup ( sema. db , definition, & markup, links_in_hover, markdown) ;
120
119
if let Some ( action) = show_implementations_action ( db, definition) {
121
120
res. actions . push ( action) ;
122
121
}
@@ -138,6 +137,9 @@ pub(crate) fn hover(
138
137
// don't highlight the entire parent node on comment hover
139
138
return None ;
140
139
}
140
+ if let res @ Some ( _) = hover_for_keyword ( & sema, links_in_hover, markdown, & token) {
141
+ return res;
142
+ }
141
143
142
144
let node = token
143
145
. ancestors ( )
@@ -272,6 +274,24 @@ fn hover_markup(
272
274
}
273
275
}
274
276
277
+ fn process_markup (
278
+ db : & RootDatabase ,
279
+ def : Definition ,
280
+ markup : & Markup ,
281
+ links_in_hover : bool ,
282
+ markdown : bool ,
283
+ ) -> Markup {
284
+ let markup = markup. as_str ( ) ;
285
+ let markup = if !markdown {
286
+ remove_markdown ( markup)
287
+ } else if links_in_hover {
288
+ rewrite_links ( db, markup, & def)
289
+ } else {
290
+ remove_links ( markup)
291
+ } ;
292
+ Markup :: from ( markup)
293
+ }
294
+
275
295
fn definition_owner_name ( db : & RootDatabase , def : & Definition ) -> Option < String > {
276
296
match def {
277
297
Definition :: Field ( f) => Some ( f. parent_def ( db) . name ( db) ) ,
@@ -304,7 +324,11 @@ fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
304
324
def. module ( db) . map ( |module| render_path ( db, module, definition_owner_name ( db, def) ) )
305
325
}
306
326
307
- fn hover_for_definition ( db : & RootDatabase , def : Definition ) -> Option < Markup > {
327
+ fn hover_for_definition (
328
+ db : & RootDatabase ,
329
+ def : Definition ,
330
+ famous_defs : Option < & FamousDefs > ,
331
+ ) -> Option < Markup > {
308
332
let mod_path = definition_mod_path ( db, & def) ;
309
333
return match def {
310
334
Definition :: Macro ( it) => {
@@ -339,7 +363,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
339
363
ModuleDef :: Static ( it) => from_def_source ( db, it, mod_path) ,
340
364
ModuleDef :: Trait ( it) => from_def_source ( db, it, mod_path) ,
341
365
ModuleDef :: TypeAlias ( it) => from_def_source ( db, it, mod_path) ,
342
- ModuleDef :: BuiltinType ( it) => Some ( Markup :: fenced_block ( & it. name ( ) ) ) ,
366
+ ModuleDef :: BuiltinType ( it) => famous_defs
367
+ . and_then ( |fd| hover_for_builtin ( fd, it) )
368
+ . or_else ( || Some ( Markup :: fenced_block ( & it. name ( ) ) ) ) ,
343
369
} ,
344
370
Definition :: Local ( it) => Some ( Markup :: fenced_block ( & it. ty ( db) . display ( db) ) ) ,
345
371
Definition :: SelfType ( impl_def) => {
@@ -380,11 +406,52 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
380
406
}
381
407
}
382
408
409
+ fn hover_for_keyword (
410
+ sema : & Semantics < RootDatabase > ,
411
+ links_in_hover : bool ,
412
+ markdown : bool ,
413
+ token : & SyntaxToken ,
414
+ ) -> Option < RangeInfo < HoverResult > > {
415
+ if !token. kind ( ) . is_keyword ( ) {
416
+ return None ;
417
+ }
418
+ let famous_defs = FamousDefs ( & sema, sema. scope ( & token. parent ( ) ) . krate ( ) ) ;
419
+ // std exposes {}_keyword modules with docstrings on the root to document keywords
420
+ let keyword_mod = format ! ( "{}_keyword" , token. text( ) ) ;
421
+ let doc_owner = find_std_module ( & famous_defs, & keyword_mod) ?;
422
+ let docs = doc_owner. attrs ( sema. db ) . docs ( ) ?;
423
+ let markup = process_markup (
424
+ sema. db ,
425
+ Definition :: ModuleDef ( doc_owner. into ( ) ) ,
426
+ & hover_markup ( Some ( docs. into ( ) ) , Some ( token. text ( ) . into ( ) ) , None ) ?,
427
+ links_in_hover,
428
+ markdown,
429
+ ) ;
430
+ Some ( RangeInfo :: new ( token. text_range ( ) , HoverResult { markup, actions : Default :: default ( ) } ) )
431
+ }
432
+
433
+ fn hover_for_builtin ( famous_defs : & FamousDefs , builtin : hir:: BuiltinType ) -> Option < Markup > {
434
+ // std exposes prim_{} modules with docstrings on the root to document the builtins
435
+ let primitive_mod = format ! ( "prim_{}" , builtin. name( ) ) ;
436
+ let doc_owner = find_std_module ( famous_defs, & primitive_mod) ?;
437
+ let docs = doc_owner. attrs ( famous_defs. 0 . db ) . docs ( ) ?;
438
+ hover_markup ( Some ( docs. into ( ) ) , Some ( builtin. name ( ) . to_string ( ) ) , None )
439
+ }
440
+
441
+ fn find_std_module ( famous_defs : & FamousDefs , name : & str ) -> Option < hir:: Module > {
442
+ let db = famous_defs. 0 . db ;
443
+ let std_crate = famous_defs. std ( ) ?;
444
+ let std_root_module = std_crate. root_module ( db) ;
445
+ std_root_module
446
+ . children ( db)
447
+ . find ( |module| module. name ( db) . map_or ( false , |module| module. to_string ( ) == name) )
448
+ }
449
+
383
450
fn pick_best ( tokens : TokenAtOffset < SyntaxToken > ) -> Option < SyntaxToken > {
384
451
return tokens. max_by_key ( priority) ;
385
452
fn priority ( n : & SyntaxToken ) -> usize {
386
453
match n. kind ( ) {
387
- IDENT | INT_NUMBER | LIFETIME_IDENT | T ! [ self ] => 3 ,
454
+ IDENT | INT_NUMBER | LIFETIME_IDENT | T ! [ self ] | T ! [ super ] | T ! [ crate ] => 3 ,
388
455
T ! [ '(' ] | T ! [ ')' ] => 2 ,
389
456
kind if kind. is_trivia ( ) => 0 ,
390
457
_ => 1 ,
@@ -3523,6 +3590,48 @@ use foo::bar::{self$0};
3523
3590
3524
3591
But this should appear
3525
3592
"# ] ] ,
3593
+ )
3594
+ }
3595
+
3596
+ #[ test]
3597
+ fn hover_keyword ( ) {
3598
+ let ra_fixture = r#"//- /main.rs crate:main deps:std
3599
+ fn f() { retur$0n; }"# ;
3600
+ let fixture = format ! ( "{}\n {}" , ra_fixture, FamousDefs :: FIXTURE ) ;
3601
+ check (
3602
+ & fixture,
3603
+ expect ! [ [ r#"
3604
+ *return*
3605
+
3606
+ ```rust
3607
+ return
3608
+ ```
3609
+
3610
+ ---
3611
+
3612
+ Docs for return_keyword
3613
+ "# ] ] ,
3614
+ ) ;
3615
+ }
3616
+
3617
+ #[ test]
3618
+ fn hover_builtin ( ) {
3619
+ let ra_fixture = r#"//- /main.rs crate:main deps:std
3620
+ cosnt _: &str$0 = ""; }"# ;
3621
+ let fixture = format ! ( "{}\n {}" , ra_fixture, FamousDefs :: FIXTURE ) ;
3622
+ check (
3623
+ & fixture,
3624
+ expect ! [ [ r#"
3625
+ *str*
3626
+
3627
+ ```rust
3628
+ str
3629
+ ```
3630
+
3631
+ ---
3632
+
3633
+ Docs for prim_str
3634
+ "# ] ] ,
3526
3635
) ;
3527
3636
}
3528
3637
}
0 commit comments