2020using Microsoft . VisualStudio . Text . Tagging ;
2121using Roslyn . Utilities ;
2222
23- namespace Microsoft . CodeAnalysis . Editor . InlineHints
23+ namespace Microsoft . CodeAnalysis . Editor . InlineHints ;
24+
25+ internal partial class InlineHintsTaggerProvider
2426{
27+ private sealed class AdornmentTagInformation (
28+ bool Classified ,
29+ TextFormattingRunProperties Format ,
30+ TagSpan < IntraTextAdornmentTag > AdornmentTagSpan )
31+ {
32+ public bool Classified { get ; } = Classified ;
33+ public TextFormattingRunProperties Format { get ; } = Format ;
34+ public TagSpan < IntraTextAdornmentTag > AdornmentTagSpan { get ; } = AdornmentTagSpan ;
35+ }
36+
2537 /// <summary>
2638 /// The purpose of this tagger is to convert the <see cref="InlineHintDataTag"/> to the <see
2739 /// cref="InlineHintsTag"/>, which actually creates the UIElement. It reacts to tags changing and updates the
2840 /// adornments accordingly.
2941 /// </summary>
30- internal sealed class InlineHintsTagger : EfficientTagger < IntraTextAdornmentTag >
42+ private sealed class InlineHintsTagger : EfficientTagger < IntraTextAdornmentTag >
3143 {
32- /// <summary>
33- /// On demand mapping of data tags to adornment tags created for them. As long as the data tags are alive,
34- /// we'll keep the corresponding adornment tags alive <em>once it has been created</em>. Note: the underlying
35- /// tagger is a view tagger, which will toss tags once they get far enough out of view. So we will only create
36- /// and cache as many adornment tags as what the underlying tagger thinks there should be tags for <em>and</em>
37- /// which have been requested by the view tagger.
38- /// </summary>
39- private static ConditionalWeakTable < TagSpan < InlineHintDataTag > , TagSpan < IntraTextAdornmentTag > > s_dataTagToAdornmentTag = new ( ) ;
40-
4144 private readonly EfficientTagger < InlineHintDataTag > _underlyingTagger ;
4245
4346 private readonly IClassificationFormatMap _formatMap ;
@@ -89,9 +92,6 @@ private void OnClassificationFormatMappingChanged(object sender, EventArgs e)
8992
9093 // When classifications change we need to rebuild the inline tags with updated Font and Color information.
9194
92- // Clear out the cached adornment tags we have associated with each data tag.
93- s_dataTagToAdornmentTag = new ( ) ;
94-
9595 if ( _format != null )
9696 {
9797 _format = null ;
@@ -101,12 +101,9 @@ private void OnClassificationFormatMappingChanged(object sender, EventArgs e)
101101
102102 private void OnGlobalOptionChanged ( object sender , object target , OptionChangedEventArgs e )
103103 {
104+ // Reclassify everything.
104105 if ( e . HasOption ( option => option . Equals ( InlineHintsViewOptionsStorage . ColorHints ) ) )
105- {
106- // Clear out cached adornments and reclassify everything.
107- s_dataTagToAdornmentTag = new ( ) ;
108106 OnTagsChanged ( this , new SnapshotSpanEventArgs ( _subjectBuffer . CurrentSnapshot . GetFullSpan ( ) ) ) ;
109- }
110107 }
111108
112109 private TextFormattingRunProperties Format
@@ -133,7 +130,10 @@ public override void AddTags(
133130 var snapshot = spans [ 0 ] . Snapshot ;
134131
135132 var document = snapshot . GetOpenDocumentInCurrentContextWithChanges ( ) ;
136- var classify = document != null && _taggerProvider . EditorOptionsService . GlobalOptions . GetOption ( InlineHintsViewOptionsStorage . ColorHints , document . Project . Language ) ;
133+ if ( document is null )
134+ return ;
135+
136+ var colorHints = _taggerProvider . EditorOptionsService . GlobalOptions . GetOption ( InlineHintsViewOptionsStorage . ColorHints , document . Project . Language ) ;
137137
138138 using var _1 = SegmentedListPool . GetPooledList < TagSpan < InlineHintDataTag > > ( out var dataTagSpans ) ;
139139 _underlyingTagger . AddTags ( spans , dataTagSpans ) ;
@@ -143,10 +143,11 @@ public override void AddTags(
143143
144144 using var _2 = PooledHashSet < int > . GetInstance ( out var seenPositions ) ;
145145
146+ var format = this . Format ;
146147 foreach ( var dataTagSpan in dataTagSpans )
147148 {
148149 if ( seenPositions . Add ( dataTagSpan . Span . Start ) )
149- adornmentTagSpans . Add ( GetAdornmentTagsSpan ( dataTagSpan , classify ) ) ;
150+ adornmentTagSpans . Add ( GetOrCreateAdornmentTagsSpan ( dataTagSpan , colorHints , format ) ) ;
150151 }
151152 }
152153 catch ( Exception e ) when ( FatalError . ReportAndPropagateUnlessCanceled ( e , ErrorSeverity . General ) )
@@ -155,28 +156,20 @@ public override void AddTags(
155156 }
156157 }
157158
158- private TagSpan < IntraTextAdornmentTag > GetAdornmentTagsSpan (
159- TagSpan < InlineHintDataTag > dataTagSpan , bool classify )
159+ private TagSpan < IntraTextAdornmentTag > GetOrCreateAdornmentTagsSpan (
160+ TagSpan < InlineHintDataTag > dataTagSpan , bool classify , TextFormattingRunProperties format )
160161 {
161- if ( s_dataTagToAdornmentTag . TryGetValue ( dataTagSpan , out var adornmentTagSpan ) )
162- return adornmentTagSpan ;
163-
164- // Extracted as a helper method to avoid closure allocations when we find the adornment span in the map.
165- return GetOrCreateAdornmentTagSpan ( dataTagSpan , classify ) ;
166- }
167-
168- private TagSpan < IntraTextAdornmentTag > GetOrCreateAdornmentTagSpan (
169- TagSpan < InlineHintDataTag > dataTagSpan , bool classify )
170- {
171- return s_dataTagToAdornmentTag . GetValue ( dataTagSpan , dataTagSpan =>
162+ // If we've never computed the adornment info, or options have changed, then compute and cache the new information.
163+ var cachedTagInformation = ( AdornmentTagInformation ? ) dataTagSpan . Tag . AdditionalData ;
164+ if ( cachedTagInformation is null || cachedTagInformation . Classified != classify || cachedTagInformation . Format != format )
172165 {
173166 var adornmentSpan = dataTagSpan . Span ;
167+ cachedTagInformation = new ( classify , format , new TagSpan < IntraTextAdornmentTag > ( adornmentSpan , InlineHintsTag . Create (
168+ dataTagSpan . Tag . Hint , format , _textView , adornmentSpan , _taggerProvider , _formatMap , classify ) ) ) ;
169+ dataTagSpan . Tag . AdditionalData = cachedTagInformation ;
170+ }
174171
175- var hintUITag = InlineHintsTag . Create (
176- dataTagSpan . Tag . Hint , Format , _textView , adornmentSpan , _taggerProvider , _formatMap , classify ) ;
177-
178- return new TagSpan < IntraTextAdornmentTag > ( adornmentSpan , hintUITag ) ;
179- } ) ;
172+ return cachedTagInformation . AdornmentTagSpan ;
180173 }
181174 }
182175}
0 commit comments