Skip to content

Commit 0fb08aa

Browse files
Avoid UI thread dependency in the constructor (#10593)
### Summary of the changes - The constructors of MEF parts must be free threaded - Get `IVsTextManager4` on demand, rather than in the constructor of `RazorLSPTextViewConnectionListener` - This removes UI thread dependency, and allows Razor to be loaded asynchronously on solution restore, reducing UI delay on startup. Fixes: #10592
2 parents f8893e8 + 36fea34 commit 0fb08aa

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/RazorLSPTextViewConnectionListener.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.VisualStudio.Text;
1515
using Microsoft.VisualStudio.Text.Editor;
1616
using Microsoft.VisualStudio.TextManager.Interop;
17+
using Microsoft.VisualStudio.Threading;
1718
using Microsoft.VisualStudio.Utilities;
1819
using IServiceProvider = System.IServiceProvider;
1920

@@ -42,7 +43,8 @@ internal class RazorLSPTextViewConnectionListener : ITextViewConnectionListener
4243
private readonly ILspEditorFeatureDetector _editorFeatureDetector;
4344
private readonly IEditorOptionsFactoryService _editorOptionsFactory;
4445
private readonly IClientSettingsManager _editorSettingsManager;
45-
private readonly IVsTextManager4 _textManager;
46+
private readonly JoinableTaskContext _joinableTaskContext;
47+
private IVsTextManager4? _textManager;
4648

4749
/// <summary>
4850
/// Protects concurrent modifications to _activeTextViews and _textBuffer's
@@ -62,16 +64,27 @@ public RazorLSPTextViewConnectionListener(
6264
IVsEditorAdaptersFactoryService editorAdaptersFactory,
6365
ILspEditorFeatureDetector editorFeatureDetector,
6466
IEditorOptionsFactoryService editorOptionsFactory,
65-
IClientSettingsManager editorSettingsManager)
67+
IClientSettingsManager editorSettingsManager,
68+
JoinableTaskContext joinableTaskContext)
6669
{
6770
_serviceProvider = serviceProvider;
6871
_editorAdaptersFactory = editorAdaptersFactory;
6972
_editorFeatureDetector = editorFeatureDetector;
7073
_editorOptionsFactory = editorOptionsFactory;
7174
_editorSettingsManager = editorSettingsManager;
72-
_textManager = (IVsTextManager4)serviceProvider.GetService(typeof(SVsTextManager));
75+
_joinableTaskContext = joinableTaskContext;
76+
}
7377

74-
Assumes.Present(_textManager);
78+
/// <summary>
79+
/// Gets instance of <see cref="IVsTextManager4"/>. This accesses COM object and requires to be called on the UI thread.
80+
/// </summary>
81+
private IVsTextManager4 TextManager
82+
{
83+
get
84+
{
85+
_joinableTaskContext.AssertUIThread();
86+
return _textManager ??= (IVsTextManager4)_serviceProvider.GetService(typeof(SVsTextManager));
87+
}
7588
}
7689

7790
public void SubjectBuffersConnected(ITextView textView, ConnectionReason reason, IReadOnlyCollection<ITextBuffer> subjectBuffers)
@@ -133,7 +146,8 @@ public void SubjectBuffersConnected(ITextView textView, ConnectionReason reason,
133146

134147
// Initialize TextView options. We only need to do this once per TextView, as the options should
135148
// automatically update and they aren't options we care about keeping track of.
136-
InitializeRazorTextViewOptions(_textManager, optionsTracker);
149+
Assumes.Present(TextManager);
150+
InitializeRazorTextViewOptions(TextManager, optionsTracker);
137151

138152
// A change in Tools->Options settings only kicks off an options changed event in the view
139153
// and not the buffer, i.e. even if we listened for TextBuffer option changes, we would never
@@ -201,7 +215,7 @@ private void RazorOptions_OptionChanged(object? sender, EditorOptionChangedEvent
201215

202216
// Retrieve current space/tabs settings from from Tools->Options and update options in
203217
// the actual editor.
204-
(ClientSpaceSettings ClientSpaceSettings, ClientCompletionSettings ClientCompletionSettings) settings = UpdateRazorEditorOptions(_textManager, optionsTracker);
218+
(ClientSpaceSettings ClientSpaceSettings, ClientCompletionSettings ClientCompletionSettings) settings = UpdateRazorEditorOptions(TextManager, optionsTracker);
205219

206220
// Keep track of accurate settings on the client side so we can easily retrieve the
207221
// options later when the server sends us a workspace/configuration request.

0 commit comments

Comments
 (0)