@@ -40,8 +40,25 @@ internal sealed class AlwaysActiveLanguageClientEventListener(
4040 /// </summary>
4141 public void StartListening ( Workspace workspace )
4242 {
43- // Trigger a fire and forget request to the VS LSP client to load our ILanguageClient.
44- Load ( ) ;
43+ _ = workspace . RegisterWorkspaceChangedHandler ( Workspace_WorkspaceChanged ) ;
44+ }
45+
46+ private void Workspace_WorkspaceChanged ( WorkspaceChangeEventArgs e )
47+ {
48+ if ( e . Kind == WorkspaceChangeKind . SolutionAdded )
49+ {
50+ // Normally VS will load the language client when an editor window is created for one of our content types,
51+ // but we want to load it as soon as a solution is loaded so workspace diagnostics work, and so 3rd parties
52+ // like Razor can use dynamic registration.
53+ Load ( ) ;
54+ }
55+ else if ( e . Kind is WorkspaceChangeKind . SolutionRemoved )
56+ {
57+ // VS will unload the language client when the solution is closed, but sometimes its a little slow to do so,
58+ // and we can end up trying to load it, above, before it has been asked to unload. We wait for the previous
59+ // instance to shutdown when we load, but we have to ensure that it at least gets signaled to do so first.
60+ Unload ( ) ;
61+ }
4562 }
4663
4764 public void StopListening ( Workspace workspace )
@@ -56,7 +73,6 @@ private void Load()
5673
5774 async Task LoadAsync ( )
5875 {
59-
6076 // Explicitly switch to the bg so that if this causes any expensive work (like mef loads) it
6177 // doesn't block the UI thread. Note, we always yield because sometimes our caller starts
6278 // on the threadpool thread but is indirectly blocked on by the UI thread.
@@ -71,6 +87,14 @@ await _languageClientBroker.Value.LoadAsync(new LanguageClientMetadata(
7187 }
7288 }
7389
90+ private void Unload ( )
91+ {
92+ // We just want to signal that an unload should happen, in case the above call to Load comes in quick.
93+ // We don't want to wait for it to complete, not do we care about errors that may occur during the unload.
94+ // The language client/server does its own error reporting as necessary.
95+ _languageClient . StopServerAsync ( ) . Forget ( ) ;
96+ }
97+
7498 /// <summary>
7599 /// The <see cref="ILanguageClientBroker.LoadAsync(ILanguageClientMetadata, ILanguageClient)"/>
76100 /// requires that we pass the <see cref="ILanguageClientMetadata"/> along with the language client instance.
0 commit comments