4
4
using System ;
5
5
using System . Collections . Generic ;
6
6
using System . Collections . Immutable ;
7
- using System . IO ;
7
+ using System . Diagnostics ;
8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
10
using Microsoft . AspNetCore . Razor . LanguageServer . Common ;
11
11
using Microsoft . AspNetCore . Razor . LanguageServer . ProjectSystem ;
12
+ using Microsoft . AspNetCore . Razor . PooledObjects ;
12
13
using Microsoft . AspNetCore . Razor . ProjectSystem ;
13
14
using Microsoft . AspNetCore . Razor . Utilities ;
14
- using Microsoft . CodeAnalysis ;
15
- using Microsoft . CodeAnalysis . Razor ;
16
15
using Microsoft . CodeAnalysis . Razor . Logging ;
17
16
using Microsoft . CodeAnalysis . Razor . ProjectSystem ;
18
17
using Microsoft . CodeAnalysis . Razor . Utilities ;
19
18
using Microsoft . CodeAnalysis . Razor . Workspaces ;
20
- using Microsoft . VisualStudio . Threading ;
21
19
22
20
namespace Microsoft . AspNetCore . Razor . LanguageServer ;
23
21
24
22
internal partial class ProjectConfigurationStateSynchronizer : IProjectConfigurationFileChangeListener , IDisposable
25
23
{
26
- private abstract record Work ( string ConfigurationFilePath ) ;
27
- private sealed record AddProject ( string ConfigurationFilePath , RazorProjectInfo ProjectInfo ) : Work ( ConfigurationFilePath ) ;
28
- private sealed record ResetProject ( string ConfigurationFilePath , ProjectKey ProjectKey ) : Work ( ConfigurationFilePath ) ;
29
- private sealed record UpdateProject ( string ConfigurationFilePath , ProjectKey ProjectKey , RazorProjectInfo ProjectInfo ) : Work ( ConfigurationFilePath ) ;
24
+ private abstract record Work ( ProjectKey ProjectKey ) ;
25
+ private sealed record ResetProject ( ProjectKey ProjectKey ) : Work ( ProjectKey ) ;
26
+ private sealed record UpdateProject ( ProjectKey ProjectKey , RazorProjectInfo ProjectInfo ) : Work ( ProjectKey ) ;
30
27
31
28
private static readonly TimeSpan s_delay = TimeSpan . FromMilliseconds ( 250 ) ;
32
29
@@ -37,8 +34,7 @@ private sealed record UpdateProject(string ConfigurationFilePath, ProjectKey Pro
37
34
private readonly CancellationTokenSource _disposeTokenSource ;
38
35
private readonly AsyncBatchingWorkQueue < Work > _workQueue ;
39
36
40
- private ImmutableDictionary < string , ProjectKey > _filePathToProjectKeyMap =
41
- ImmutableDictionary < string , ProjectKey > . Empty . WithComparers ( keyComparer : FilePathComparer . Instance ) ;
37
+ private readonly Dictionary < ProjectKey , ResetProject > _resetProjectMap = new ( ) ;
42
38
43
39
public ProjectConfigurationStateSynchronizer (
44
40
IRazorProjectService projectService ,
@@ -67,44 +63,26 @@ public void Dispose()
67
63
_disposeTokenSource . Cancel ( ) ;
68
64
_disposeTokenSource . Dispose ( ) ;
69
65
}
66
+
70
67
private async ValueTask ProcessBatchAsync ( ImmutableArray < Work > items , CancellationToken token )
71
68
{
72
69
foreach ( var item in items . GetMostRecentUniqueItems ( Comparer . Instance ) )
73
70
{
71
+ if ( token . IsCancellationRequested )
72
+ {
73
+ return ;
74
+ }
75
+
74
76
var itemTask = item switch
75
77
{
76
- AddProject ( var configurationFilePath , var projectInfo ) => AddProjectAsync ( configurationFilePath , projectInfo , token ) ,
77
- ResetProject ( _ , var projectKey ) => ResetProjectAsync ( projectKey , token ) ,
78
- UpdateProject ( _ , var projectKey , var projectInfo ) => UpdateProjectAsync ( projectKey , projectInfo , token ) ,
78
+ ResetProject ( var projectKey ) => ResetProjectAsync ( projectKey , token ) ,
79
+ UpdateProject ( var projectKey , var projectInfo ) => UpdateProjectAsync ( projectKey , projectInfo , token ) ,
79
80
_ => Assumed . Unreachable < Task > ( )
80
81
} ;
81
82
82
83
await itemTask . ConfigureAwait ( false ) ;
83
84
}
84
85
85
- async Task AddProjectAsync ( string configurationFilePath , RazorProjectInfo projectInfo , CancellationToken token )
86
- {
87
- var projectFilePath = FilePathNormalizer . Normalize ( projectInfo . FilePath ) ;
88
- var intermediateOutputPath = FilePathNormalizer . GetNormalizedDirectoryName ( configurationFilePath ) ;
89
-
90
- var projectKey = await _projectService
91
- . AddProjectAsync (
92
- projectFilePath ,
93
- intermediateOutputPath ,
94
- projectInfo . Configuration ,
95
- projectInfo . RootNamespace ,
96
- projectInfo . DisplayName ,
97
- token )
98
- . ConfigureAwait ( false ) ;
99
-
100
- _logger . LogInformation ( $ "Added { projectKey . Id } .") ;
101
-
102
- ImmutableInterlocked . AddOrUpdate ( ref _filePathToProjectKeyMap , configurationFilePath , projectKey , static ( k , v ) => v ) ;
103
- _logger . LogInformation ( $ "Project configuration file added for project '{ projectFilePath } ': '{ configurationFilePath } '") ;
104
-
105
- await UpdateProjectAsync ( projectKey , projectInfo , token ) . ConfigureAwait ( false ) ;
106
- }
107
-
108
86
Task ResetProjectAsync ( ProjectKey projectKey , CancellationToken token )
109
87
{
110
88
_logger . LogInformation ( $ "Resetting { projectKey . Id } .") ;
@@ -125,8 +103,9 @@ Task UpdateProjectAsync(ProjectKey projectKey, RazorProjectInfo projectInfo, Can
125
103
_logger . LogInformation ( $ "Updating { projectKey . Id } .") ;
126
104
127
105
return _projectService
128
- . UpdateProjectAsync (
106
+ . AddOrUpdateProjectAsync (
129
107
projectKey ,
108
+ projectInfo . FilePath ,
130
109
projectInfo . Configuration ,
131
110
projectInfo . RootNamespace ,
132
111
projectInfo . DisplayName ,
@@ -138,55 +117,25 @@ Task UpdateProjectAsync(ProjectKey projectKey, RazorProjectInfo projectInfo, Can
138
117
139
118
public void ProjectConfigurationFileChanged ( ProjectConfigurationFileChangeEventArgs args )
140
119
{
141
- var configurationFilePath = FilePathNormalizer . Normalize ( args . ConfigurationFilePath ) ;
142
-
143
120
switch ( args . Kind )
144
121
{
145
122
case RazorFileChangeKind . Changed :
146
123
{
147
124
if ( args . TryDeserialize ( _options , out var projectInfo ) )
148
125
{
149
- if ( _filePathToProjectKeyMap . TryGetValue ( configurationFilePath , out var projectKey ) )
150
- {
151
- _logger . LogInformation ( $ """
152
- Configuration file changed for project '{ projectKey . Id } '.
153
- Configuration file path: '{ configurationFilePath } '
154
- """ ) ;
155
-
156
- _workQueue . AddWork ( new UpdateProject ( configurationFilePath , projectKey , projectInfo ) ) ;
157
- }
158
- else
159
- {
160
- _logger . LogWarning ( $ """
161
- Adding project for previously unseen configuration file.
162
- Configuration file path: '{ configurationFilePath } '
163
- """ ) ;
164
-
165
- _workQueue . AddWork ( new AddProject ( configurationFilePath , projectInfo ) ) ;
166
- }
126
+ var projectKey = ProjectKey . From ( projectInfo ) ;
127
+ _logger . LogInformation ( $ "Configuration file changed for project '{ projectKey . Id } '.") ;
128
+
129
+ _workQueue . AddWork ( new UpdateProject ( projectKey , projectInfo ) ) ;
167
130
}
168
131
else
169
132
{
170
- if ( _filePathToProjectKeyMap . TryGetValue ( configurationFilePath , out var projectKey ) )
171
- {
172
- _logger . LogWarning ( $ """
173
- Failed to deserialize after change to configuration file for project '{ projectKey . Id } '.
174
- Configuration file path: '{ configurationFilePath } '
175
- """ ) ;
176
-
177
- // We found the last associated project file for the configuration file. Reset the project since we can't
178
- // accurately determine its configurations.
179
-
180
- _workQueue . AddWork ( new ResetProject ( configurationFilePath , projectKey ) ) ;
181
- }
182
- else
183
- {
184
- // Could not resolve an associated project file.
185
- _logger . LogWarning ( $ """
186
- Failed to deserialize after change to previously unseen configuration file.
187
- Configuration file path: '{ configurationFilePath } '
188
- """ ) ;
189
- }
133
+ var projectKey = args . GetProjectKey ( ) ;
134
+ _logger . LogWarning ( $ "Failed to deserialize after change to configuration file for project '{ projectKey . Id } '.") ;
135
+
136
+ // We found the last associated project file for the configuration file. Reset the project since we can't
137
+ // accurately determine its configurations.
138
+ _workQueue . AddWork ( new ResetProject ( projectKey ) ) ;
190
139
}
191
140
}
192
141
@@ -196,39 +145,28 @@ Failed to deserialize after change to previously unseen configuration file.
196
145
{
197
146
if ( args . TryDeserialize ( _options , out var projectInfo ) )
198
147
{
199
- _workQueue . AddWork ( new AddProject ( configurationFilePath , projectInfo ) ) ;
148
+ var projectKey = ProjectKey . From ( projectInfo ) ;
149
+ _logger . LogInformation ( $ "Configuration file added for project '{ projectKey . Id } '.") ;
150
+
151
+ // Update will add the project if it doesn't exist
152
+ _workQueue . AddWork ( new UpdateProject ( projectKey , projectInfo ) ) ;
200
153
}
201
154
else
202
155
{
203
156
// This is the first time we've seen this configuration file, but we can't deserialize it.
204
157
// The only thing we can really do is issue a warning.
205
- _logger . LogWarning ( $ """
206
- Failed to deserialize previously unseen configuration file.
207
- Configuration file path: '{ configurationFilePath } '
208
- """ ) ;
158
+ _logger . LogWarning ( $ "Failed to deserialize previously unseen configuration file '{ args . ConfigurationFilePath } '") ;
209
159
}
210
160
}
211
161
212
162
break ;
213
163
214
164
case RazorFileChangeKind . Removed :
215
165
{
216
- if ( ImmutableInterlocked . TryRemove ( ref _filePathToProjectKeyMap , configurationFilePath , out var projectKey ) )
217
- {
218
- _logger . LogInformation ( $ """
219
- Configuration file removed for project '{ projectKey } '.
220
- Configuration file path: '{ configurationFilePath } '
221
- """ ) ;
166
+ var projectKey = args . GetProjectKey ( ) ;
167
+ _logger . LogInformation ( $ "Configuration file removed for project '{ projectKey } '.") ;
222
168
223
- _workQueue . AddWork ( new ResetProject ( configurationFilePath , projectKey ) ) ;
224
- }
225
- else
226
- {
227
- _logger . LogWarning ( $ """
228
- Failed to resolve associated project on configuration removed event.
229
- Configuration file path: '{ configurationFilePath } '
230
- """ ) ;
231
- }
169
+ _workQueue . AddWork ( new ResetProject ( projectKey ) ) ;
232
170
}
233
171
234
172
break ;
0 commit comments