Skip to content

Commit 476f3c3

Browse files
committed
Unitialize Lsp options in OOP when the server is disposed
1 parent 7b05d27 commit 476f3c3

File tree

13 files changed

+65
-8
lines changed

13 files changed

+65
-8
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CohostStartupService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
1111
using Microsoft.CodeAnalysis.Razor.Logging;
1212
using Microsoft.CodeAnalysis.Razor.Remote;
13+
using Microsoft.VisualStudio.Threading;
1314

1415
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
1516

@@ -60,5 +61,6 @@ public override async Task RazorActivatedAsync(ClientCapabilities clientCapabili
6061

6162
public override void Dispose()
6263
{
64+
_remoteServiceInvoker.UninitializeLspAsync().Forget();
6365
}
6466
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/AbstractClientCapabilitiesService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal abstract class AbstractClientCapabilitiesService : IClientCapabilitiesS
1313

1414
public VSInternalClientCapabilities ClientCapabilities => _clientCapabilities ?? throw new InvalidOperationException("Client capabilities requested before initialized.");
1515

16-
public void SetCapabilities(VSInternalClientCapabilities clientCapabilities)
16+
public void SetCapabilities(VSInternalClientCapabilities? clientCapabilities)
1717
{
1818
_clientCapabilities = clientCapabilities;
1919
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteClientInitializationService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ internal interface IRemoteClientInitializationService : IRemoteJsonService
1111
ValueTask InitializeAsync(RemoteClientInitializationOptions initializationOptions, CancellationToken cancellationToken);
1212

1313
ValueTask InitializeLSPAsync(RemoteClientLSPInitializationOptions lspInitializationOptions, CancellationToken cancellationToken);
14+
15+
ValueTask UninitializeLspAsync(CancellationToken cancellationToken);
1416
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteServiceInvoker.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ internal interface IRemoteServiceInvoker
1313
{
1414
ValueTask InitializeAsync();
1515

16+
ValueTask UninitializeLspAsync();
17+
1618
ValueTask<TResult?> TryInvokeAsync<TService, TResult>(
1719
Solution solution,
1820
Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation,

src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteClientCapabilitiesService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ public void OnLspInitialized(RemoteClientLSPInitializationOptions options)
1919

2020
public void OnLspUninitialized()
2121
{
22+
SetCapabilities(null);
2223
}
2324
}

src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Initialization/RemoteClientInitializationService.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,16 @@ public ValueTask InitializeLSPAsync(RemoteClientLSPInitializationOptions options
3838
return default;
3939
},
4040
cancellationToken);
41+
42+
public ValueTask UninitializeLspAsync(CancellationToken cancellationToken)
43+
=> RunServiceAsync(ct =>
44+
{
45+
foreach (var service in _lspLifetimeServices)
46+
{
47+
service.OnLspUninitialized();
48+
}
49+
50+
return default;
51+
},
52+
cancellationToken);
4153
}

src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteSemanticTokensLegendService.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,11 @@ internal sealed class RemoteSemanticTokensLegendService : ISemanticTokensLegendS
2323

2424
public void OnLspInitialized(RemoteClientLSPInitializationOptions options)
2525
{
26-
SetLegend(options.TokenTypes, options.TokenModifiers);
26+
_tokenTypes = new SemanticTokenTypes(options.TokenTypes);
27+
_tokenModifiers = new SemanticTokenModifiers(options.TokenModifiers);
2728
}
2829

2930
public void OnLspUninitialized()
3031
{
3132
}
32-
33-
public void SetLegend(string[] tokenTypes, string[] tokenModifiers)
34-
{
35-
_tokenTypes = new SemanticTokenTypes(tokenTypes);
36-
_tokenModifiers = new SemanticTokenModifiers(tokenModifiers);
37-
}
3833
}

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ internal sealed class RemoteServiceInvoker(
4848
private readonly object _gate = new();
4949
private Task? _initializeOOPTask;
5050
private Task? _initializeLspTask;
51+
private CancellationTokenSource? _uninitializeLspTokenSource;
5152

5253
public void Dispose()
5354
{
@@ -162,6 +163,8 @@ async Task InitializeCoreAsync(bool oopInitialized, bool lspInitialized)
162163
{
163164
lock (_gate)
164165
{
166+
_uninitializeLspTokenSource?.Cancel();
167+
165168
_initializeLspTask ??= InitializeLspAsync(remoteClient);
166169
}
167170

@@ -216,4 +219,34 @@ Task InitializeLspAsync(RazorRemoteHostClient remoteClient)
216219
}
217220
}
218221
}
222+
223+
public ValueTask UninitializeLspAsync()
224+
{
225+
var lspInitialized = _initializeLspTask is { Status: TaskStatus.RanToCompletion };
226+
227+
lock (_gate)
228+
{
229+
_uninitializeLspTokenSource?.Cancel();
230+
231+
_initializeLspTask = null;
232+
_uninitializeLspTokenSource = new();
233+
}
234+
235+
return lspInitialized
236+
? new(UninitializeCoreAsync(_uninitializeLspTokenSource.Token))
237+
: default;
238+
239+
async Task UninitializeCoreAsync(CancellationToken cancellationToken)
240+
{
241+
// Note: IRemoteClientInitializationService is an IRemoteJsonService
242+
var remoteClient = await _lazyJsonClient
243+
.GetValueAsync(cancellationToken)
244+
.ConfigureAwait(false);
245+
246+
await remoteClient
247+
.TryInvokeAsync<IRemoteClientInitializationService>(
248+
(s, ct) => s.UninitializeLspAsync(ct),
249+
cancellationToken);
250+
}
251+
}
219252
}

src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServiceInvoker.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ internal class VSCodeRemoteServiceInvoker(
3131

3232
public ValueTask InitializeAsync() => ValueTask.CompletedTask; // Initialization in VS Code is handled in VSCodeRemoteServicesInitializer
3333

34+
public ValueTask UninitializeLspAsync() => ValueTask.CompletedTask; // When VS Code wants to un-initialize a language server, it just kills the process
35+
3436
public async ValueTask<TResult?> TryInvokeAsync<TService, TResult>(
3537
Solution solution,
3638
Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation,

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostRoslynRenameTest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ internal void SetInvoker(TestRemoteServiceInvoker remoteServiceInvoker)
204204

205205
public ValueTask InitializeAsync() => throw new NotImplementedException();
206206

207+
public ValueTask UninitializeLspAsync() => throw new NotImplementedException();
208+
207209
public ValueTask<TResult?> TryInvokeAsync<TService, TResult>(Solution solution, Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation, CancellationToken cancellationToken, [CallerFilePath] string? callerFilePath = null, [CallerMemberName] string? callerMemberName = null) where TService : class
208210
=> _remoteServiceInvoker.AssumeNotNull().TryInvokeAsync(solution, invocation, cancellationToken, callerFilePath, callerMemberName);
209211

0 commit comments

Comments
 (0)