9
9
using Microsoft . CodeAnalysis . Editor . Shared . Extensions ;
10
10
using Microsoft . CodeAnalysis . Editor . Shared . Tagging ;
11
11
using Microsoft . CodeAnalysis . Editor . Tagging ;
12
- using Microsoft . CodeAnalysis . ErrorReporting ;
13
12
using Microsoft . CodeAnalysis . Host ;
14
13
using Microsoft . CodeAnalysis . Internal . Log ;
15
- using Microsoft . CodeAnalysis . Shared . TestHooks ;
16
14
using Microsoft . CodeAnalysis . Text ;
17
15
using Microsoft . CodeAnalysis . Text . Shared . Extensions ;
18
16
using Microsoft . CodeAnalysis . Threading ;
@@ -44,8 +42,8 @@ private sealed record CachedServices(
44
42
private static readonly object s_uniqueKey = new ( ) ;
45
43
46
44
private readonly SyntacticClassificationTaggerProvider _taggerProvider ;
47
- private readonly ITextBuffer2 _subjectBuffer ;
48
- private readonly WorkspaceRegistration _workspaceRegistration ;
45
+ private readonly ITextBuffer _subjectBuffer ;
46
+ private readonly ITaggerEventSource _taggerEventSource ;
49
47
50
48
private readonly CancellationTokenSource _disposalCancellationSource = new ( ) ;
51
49
@@ -61,10 +59,6 @@ private sealed record CachedServices(
61
59
/// </summary>
62
60
private readonly TimeSpan _diffTimeout ;
63
61
64
- private Workspace ? _workspace ;
65
- private WorkspaceEventRegistration ? _workspaceChangedDisposer ;
66
- private WorkspaceEventRegistration ? _workspaceDocumentActiveContextChangedDisposer ;
67
-
68
62
/// <summary>
69
63
/// Cached values for the last services we computed for a particular <see cref="Workspace"/> and <see
70
64
/// cref="IContentType"/>. These rarely change, and are expensive enough to show up in very hot scenarios (like
@@ -89,12 +83,11 @@ private sealed record CachedServices(
89
83
/// again and again to find exactly same answer
90
84
/// </summary>
91
85
private readonly ClassifiedLineCache _lineCache ;
92
-
93
86
private int _taggerReferenceCount ;
94
87
95
88
public TagComputer (
96
89
SyntacticClassificationTaggerProvider taggerProvider ,
97
- ITextBuffer2 subjectBuffer ,
90
+ ITextBuffer subjectBuffer ,
98
91
TimeSpan diffTimeout )
99
92
{
100
93
_taggerProvider = taggerProvider ;
@@ -109,13 +102,19 @@ public TagComputer(
109
102
110
103
_lineCache = new ClassifiedLineCache ( taggerProvider . ThreadingContext ) ;
111
104
112
- _workspaceRegistration = Workspace . GetWorkspaceRegistration ( subjectBuffer . AsTextContainer ( ) ) ;
113
- _workspaceRegistration . WorkspaceChanged += OnWorkspaceRegistrationChanged ;
105
+ _taggerEventSource = TaggerEventSources . Compose (
106
+ TaggerEventSources . OnWorkspaceChanged ( subjectBuffer , taggerProvider . _listener ) ,
107
+ TaggerEventSources . OnWorkspaceRegistrationChanged ( subjectBuffer ) ,
108
+ TaggerEventSources . OnDocumentActiveContextChanged ( subjectBuffer ) ,
109
+ TaggerEventSources . OnTextChanged ( subjectBuffer ) ,
110
+ TaggerEventSources . OnParseOptionChanged ( subjectBuffer ) ) ;
111
+
112
+ _taggerEventSource . Connect ( ) ;
114
113
115
- if ( _workspaceRegistration . Workspace != null )
116
- ConnectToWorkspace ( _workspaceRegistration . Workspace ) ;
114
+ _taggerEventSource . Changed += OnEventSourceChanged ;
117
115
118
- _subjectBuffer . ChangedOnBackground += this . OnSubjectBufferChanged ;
116
+ // Kick off work to classify the current snapshot of the subject buffer.
117
+ _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
119
118
}
120
119
121
120
public static TagComputer GetOrCreate (
@@ -130,14 +129,13 @@ public static TagComputer GetOrCreate(
130
129
return tagComputer ;
131
130
}
132
131
133
- private void DisconnectTagComputer ( )
134
- => _subjectBuffer . Properties . RemoveProperty ( s_uniqueKey ) ;
135
-
136
132
public event EventHandler < SnapshotSpanEventArgs > ? TagsChanged ;
137
133
138
134
private ( SolutionServices solutionServices , IClassificationService classificationService ) ? TryGetClassificationService ( ITextSnapshot snapshot )
139
135
{
140
- var workspace = _workspace ;
136
+ var document = snapshot . GetOpenDocumentInCurrentContextWithChanges ( ) ;
137
+ var workspace = document ? . Project . Solution . Workspace ;
138
+
141
139
var contentType = snapshot . ContentType ;
142
140
var lastCachedServices = _lastCachedServices ;
143
141
@@ -158,45 +156,6 @@ private void DisconnectTagComputer()
158
156
return ( lastCachedServices . SolutionServices , lastCachedServices . ClassificationService ) ;
159
157
}
160
158
161
- #region Workspace Hookup
162
-
163
- private void OnWorkspaceRegistrationChanged ( object ? sender , EventArgs e )
164
- {
165
- var token = _taggerProvider . _listener . BeginAsyncOperation ( nameof ( OnWorkspaceRegistrationChanged ) ) ;
166
- var task = SwitchToMainThreadAndHookupWorkspaceAsync ( ) ;
167
- task . CompletesAsyncOperation ( token ) ;
168
- }
169
-
170
- private async Task SwitchToMainThreadAndHookupWorkspaceAsync ( )
171
- {
172
- try
173
- {
174
- await _taggerProvider . ThreadingContext . JoinableTaskFactory . SwitchToMainThreadAsync ( _disposalCancellationSource . Token ) ;
175
-
176
- // We both try to connect synchronously, and register for workspace registration events.
177
- // It's possible (particularly in tests), to connect in the startup path, but then get a
178
- // previously scheduled, but not yet delivered event. Don't bother connecting to the
179
- // same workspace again in that case.
180
- var newWorkspace = _workspaceRegistration . Workspace ;
181
- if ( newWorkspace == _workspace )
182
- return ;
183
-
184
- DisconnectFromWorkspace ( ) ;
185
-
186
- if ( newWorkspace != null )
187
- ConnectToWorkspace ( newWorkspace ) ;
188
- }
189
- catch ( OperationCanceledException )
190
- {
191
- // can happen if we were disposed of.
192
- }
193
- catch ( Exception e ) when ( FatalError . ReportAndCatch ( e ) )
194
- {
195
- // We were in a fire and forget task. So just report the NFW and do not let
196
- // this bleed out to an unhandled exception.
197
- }
198
- }
199
-
200
159
internal void IncrementReferenceCount ( )
201
160
{
202
161
_taggerProvider . ThreadingContext . ThrowIfNotOnUIThread ( ) ;
@@ -213,103 +172,16 @@ internal void DecrementReferenceCount()
213
172
// stop any bg work we're doing.
214
173
_disposalCancellationSource . Cancel ( ) ;
215
174
216
- _subjectBuffer . ChangedOnBackground -= this . OnSubjectBufferChanged ;
175
+ _taggerEventSource . Changed -= OnEventSourceChanged ;
176
+ _taggerEventSource . Disconnect ( ) ;
217
177
218
- DisconnectFromWorkspace ( ) ;
219
- _workspaceRegistration . WorkspaceChanged -= OnWorkspaceRegistrationChanged ;
220
- DisconnectTagComputer ( ) ;
178
+ _subjectBuffer . Properties . RemoveProperty ( s_uniqueKey ) ;
179
+ _lastCachedServices = null ;
221
180
}
222
181
}
223
182
224
- private void ConnectToWorkspace ( Workspace workspace )
225
- {
226
- _taggerProvider . ThreadingContext . ThrowIfNotOnUIThread ( ) ;
227
-
228
- _workspace = workspace ;
229
- _workspaceChangedDisposer = _workspace . RegisterWorkspaceChangedHandler ( this . OnWorkspaceChanged ) ;
230
- _workspaceDocumentActiveContextChangedDisposer = _workspace . RegisterDocumentActiveContextChangedHandler ( this . OnDocumentActiveContextChanged ) ;
231
-
232
- // Now that we've connected to the workspace, kick off work to reclassify this buffer.
233
- _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
234
- }
235
-
236
- public void DisconnectFromWorkspace ( )
237
- {
238
- _taggerProvider . ThreadingContext . ThrowIfNotOnUIThread ( ) ;
239
- _lastCachedServices = null ;
240
-
241
- lock ( _gate )
242
- {
243
- _lastProcessedData = null ;
244
- }
245
-
246
- if ( _workspace != null )
247
- {
248
- _workspaceChangedDisposer ? . Dispose ( ) ;
249
- _workspaceChangedDisposer = null ;
250
-
251
- _workspaceDocumentActiveContextChangedDisposer ? . Dispose ( ) ;
252
- _workspaceDocumentActiveContextChangedDisposer = null ;
253
-
254
- _workspace = null ;
255
-
256
- // Now that we've disconnected to the workspace, kick off work to reclassify this buffer.
257
- _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
258
- }
259
- }
260
-
261
- #endregion
262
-
263
- #region Event Handling
264
-
265
- private void OnSubjectBufferChanged ( object ? sender , TextContentChangedEventArgs args )
266
- {
267
- // we know a change to our buffer is always affecting this document. So we can
268
- // just enqueue the work to reclassify things unilaterally.
269
- _workQueue . AddWork ( args . After ) ;
270
- }
271
-
272
- private void OnDocumentActiveContextChanged ( DocumentActiveContextChangedEventArgs args )
273
- {
274
- if ( _workspace == null )
275
- return ;
276
-
277
- var documentId = args . NewActiveContextDocumentId ;
278
- var bufferDocumentId = _workspace . GetDocumentIdInCurrentContext ( _subjectBuffer . AsTextContainer ( ) ) ;
279
- if ( bufferDocumentId != documentId )
280
- return ;
281
-
282
- _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
283
- }
284
-
285
- private void OnWorkspaceChanged ( WorkspaceChangeEventArgs args )
286
- {
287
- // We may be getting an event for a workspace we already disconnected from. If so,
288
- // ignore them. We won't be able to find the Document corresponding to our text buffer,
289
- // so we can't reasonably classify this anyways.
290
- var workspace = _workspace ;
291
- if ( args . NewSolution . Workspace != workspace )
292
- return ;
293
-
294
- if ( args . Kind != WorkspaceChangeKind . ProjectChanged )
295
- return ;
296
-
297
- var documentId = workspace . GetDocumentIdInCurrentContext ( _subjectBuffer . AsTextContainer ( ) ) ;
298
- if ( args . ProjectId != documentId ? . ProjectId )
299
- return ;
300
-
301
- var oldProject = args . OldSolution . GetProject ( args . ProjectId ) ;
302
- var newProject = args . NewSolution . GetProject ( args . ProjectId ) ;
303
-
304
- // In case of parse options change reclassify the doc as it may have affected things
305
- // like preprocessor directives.
306
- if ( Equals ( oldProject ? . ParseOptions , newProject ? . ParseOptions ) )
307
- return ;
308
-
309
- _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
310
- }
311
-
312
- #endregion
183
+ private void OnEventSourceChanged ( object ? sender , EventArgs e )
184
+ => _workQueue . AddWork ( _subjectBuffer . CurrentSnapshot ) ;
313
185
314
186
/// <summary>
315
187
/// Parses the document in the background and determines what has changed to report to
@@ -416,7 +288,7 @@ public void AddTags(NormalizedSnapshotSpanCollection spans, SegmentedList<TagSpa
416
288
private void AddTagsWorker ( NormalizedSnapshotSpanCollection spans , SegmentedList < TagSpan < IClassificationTag > > tags )
417
289
{
418
290
_taggerProvider . ThreadingContext . ThrowIfNotOnUIThread ( ) ;
419
- if ( spans . Count == 0 || _workspace == null )
291
+ if ( spans . Count == 0 )
420
292
return ;
421
293
422
294
var snapshot = spans [ 0 ] . Snapshot ;
0 commit comments