1
1
use std:: {
2
2
fmt:: { self , Write } ,
3
- mem:: take,
3
+ mem:: { self , take} ,
4
4
} ;
5
5
6
6
use either:: Either ;
@@ -297,6 +297,17 @@ pub struct InlayHintsConfig {
297
297
pub closing_brace_hints_min_lines : Option < usize > ,
298
298
pub fields_to_resolve : InlayFieldsToResolve ,
299
299
}
300
+ impl InlayHintsConfig {
301
+ fn lazy_text_edit ( & self , finish : impl FnOnce ( ) -> TextEdit ) -> Lazy < TextEdit > {
302
+ if self . fields_to_resolve . resolve_text_edits {
303
+ Lazy :: Lazy
304
+ } else {
305
+ let edit = finish ( ) ;
306
+ never ! ( edit. is_empty( ) , "inlay hint produced an empty text edit" ) ;
307
+ Lazy :: Computed ( edit)
308
+ }
309
+ }
310
+ }
300
311
301
312
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
302
313
pub struct InlayFieldsToResolve {
@@ -408,12 +419,32 @@ pub struct InlayHint {
408
419
/// The actual label to show in the inlay hint.
409
420
pub label : InlayHintLabel ,
410
421
/// Text edit to apply when "accepting" this inlay hint.
411
- pub text_edit : Option < TextEdit > ,
422
+ pub text_edit : Option < Lazy < TextEdit > > ,
412
423
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
413
424
/// hint does not support resolving.
414
425
pub resolve_parent : Option < TextRange > ,
415
426
}
416
427
428
+ /// A type signaling that a value is either computed, or is available for computation.
429
+ #[ derive( Clone , Debug ) ]
430
+ pub enum Lazy < T > {
431
+ Computed ( T ) ,
432
+ Lazy ,
433
+ }
434
+
435
+ impl < T > Lazy < T > {
436
+ pub fn computed ( self ) -> Option < T > {
437
+ match self {
438
+ Lazy :: Computed ( it) => Some ( it) ,
439
+ _ => None ,
440
+ }
441
+ }
442
+
443
+ pub fn is_lazy ( & self ) -> bool {
444
+ matches ! ( self , Self :: Lazy )
445
+ }
446
+ }
447
+
417
448
impl std:: hash:: Hash for InlayHint {
418
449
fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
419
450
self . range . hash ( state) ;
@@ -422,7 +453,7 @@ impl std::hash::Hash for InlayHint {
422
453
self . pad_right . hash ( state) ;
423
454
self . kind . hash ( state) ;
424
455
self . label . hash ( state) ;
425
- self . text_edit . is_some ( ) . hash ( state) ;
456
+ mem :: discriminant ( & self . text_edit ) . hash ( state) ;
426
457
}
427
458
}
428
459
@@ -439,10 +470,6 @@ impl InlayHint {
439
470
resolve_parent : None ,
440
471
}
441
472
}
442
-
443
- pub fn needs_resolve ( & self ) -> Option < TextRange > {
444
- self . resolve_parent . filter ( |_| self . text_edit . is_some ( ) || self . label . needs_resolve ( ) )
445
- }
446
473
}
447
474
448
475
#[ derive( Debug , Hash ) ]
@@ -503,10 +530,6 @@ impl InlayHintLabel {
503
530
}
504
531
self . parts . push ( part) ;
505
532
}
506
-
507
- pub fn needs_resolve ( & self ) -> bool {
508
- self . parts . iter ( ) . any ( |part| part. linked_location . is_some ( ) || part. tooltip . is_some ( ) )
509
- }
510
533
}
511
534
512
535
impl From < String > for InlayHintLabel {
@@ -725,19 +748,22 @@ fn hint_iterator(
725
748
726
749
fn ty_to_text_edit (
727
750
sema : & Semantics < ' _ , RootDatabase > ,
751
+ config : & InlayHintsConfig ,
728
752
node_for_hint : & SyntaxNode ,
729
753
ty : & hir:: Type ,
730
754
offset_to_insert : TextSize ,
731
- prefix : String ,
732
- ) -> Option < TextEdit > {
733
- let scope = sema. scope ( node_for_hint) ?;
755
+ prefix : impl Into < String > ,
756
+ ) -> Option < Lazy < TextEdit > > {
734
757
// FIXME: Limit the length and bail out on excess somehow?
735
- let rendered = ty. display_source_code ( scope. db , scope. module ( ) . into ( ) , false ) . ok ( ) ?;
736
-
737
- let mut builder = TextEdit :: builder ( ) ;
738
- builder. insert ( offset_to_insert, prefix) ;
739
- builder. insert ( offset_to_insert, rendered) ;
740
- Some ( builder. finish ( ) )
758
+ let rendered = sema
759
+ . scope ( node_for_hint)
760
+ . and_then ( |scope| ty. display_source_code ( scope. db , scope. module ( ) . into ( ) , false ) . ok ( ) ) ?;
761
+ Some ( config. lazy_text_edit ( || {
762
+ let mut builder = TextEdit :: builder ( ) ;
763
+ builder. insert ( offset_to_insert, prefix. into ( ) ) ;
764
+ builder. insert ( offset_to_insert, rendered) ;
765
+ builder. finish ( )
766
+ } ) )
741
767
}
742
768
743
769
fn closure_has_block_body ( closure : & ast:: ClosureExpr ) -> bool {
@@ -847,7 +873,7 @@ mod tests {
847
873
848
874
let edits = inlay_hints
849
875
. into_iter ( )
850
- . filter_map ( |hint| hint. text_edit )
876
+ . filter_map ( |hint| hint. text_edit ? . computed ( ) )
851
877
. reduce ( |mut acc, next| {
852
878
acc. union ( next) . expect ( "merging text edits failed" ) ;
853
879
acc
@@ -867,7 +893,8 @@ mod tests {
867
893
let ( analysis, file_id) = fixture:: file ( ra_fixture) ;
868
894
let inlay_hints = analysis. inlay_hints ( & config, file_id, None ) . unwrap ( ) ;
869
895
870
- let edits: Vec < _ > = inlay_hints. into_iter ( ) . filter_map ( |hint| hint. text_edit ) . collect ( ) ;
896
+ let edits: Vec < _ > =
897
+ inlay_hints. into_iter ( ) . filter_map ( |hint| hint. text_edit ?. computed ( ) ) . collect ( ) ;
871
898
872
899
assert ! ( edits. is_empty( ) , "unexpected edits: {edits:?}" ) ;
873
900
}
0 commit comments