diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs index 0caa2228ab91d..c4e60eaf3b735 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs @@ -14,11 +14,9 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Threading; -using Microsoft.VisualStudio; using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; using Task = System.Threading.Tasks.Task; namespace Microsoft.CodeAnalysis.ColorSchemes; @@ -42,7 +40,6 @@ internal sealed partial class ColorSchemeApplier [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public ColorSchemeApplier( IThreadingContext threadingContext, - IVsService fontAndColorStorage, IGlobalOptionService globalOptions, SVsServiceProvider serviceProvider, IAsynchronousOperationListenerProvider listenerProvider) diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs index 6758cf78d0014..4c40f1eff0d0a 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs @@ -58,32 +58,32 @@ private async Task PackageInitializationMainThreadAsync(IProgress - { - // Ensure we're on the BG when creating the language service. - await TaskScheduler.Default; - - // Create the language service, tell it to set itself up, then store it in a field - // so we can notify it that it's time to clean up. - _languageService = CreateLanguageService(); - await _languageService.SetupAsync(cancellationToken).ConfigureAwait(false); - - return _languageService.ComAggregate!; - }); - var miscellaneousFilesWorkspace = this.ComponentModel.GetService(); // awaiting an IVsTask guarantees to return on the captured context await shell.LoadPackageAsync(Guids.RoslynPackageId); - RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace); + packageRegistrationTasks.AddTask( + isMainThreadTask: false, + task: (IProgress progress, PackageRegistrationTasks packageRegistrationTasks, CancellationToken cancellationToken) => + { + RegisterLanguageService(typeof(TLanguageService), async cancellationToken => + { + // Ensure we're on the BG when creating the language service. + await TaskScheduler.Default; - if (!_shell.IsInCommandLineMode()) - { - // not every derived package support object browser and for those languages - // this is a no op - RegisterObjectBrowserLibraryManager(); - } + // Create the language service, tell it to set itself up, then store it in a field + // so we can notify it that it's time to clean up. + _languageService = CreateLanguageService(); + await _languageService.SetupAsync(cancellationToken).ConfigureAwait(false); + + return _languageService.ComAggregate!; + }); + + RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace); + + return Task.CompletedTask; + }); } protected override async Task OnAfterPackageLoadedAsync(CancellationToken cancellationToken) @@ -92,6 +92,13 @@ protected override async Task OnAfterPackageLoadedAsync(CancellationToken cancel await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + if (_shell != null && !_shell.IsInCommandLineMode()) + { + // not every derived package support object browser and for those languages + // this is a no op + RegisterObjectBrowserLibraryManager(); + } + LoadComponentsInUIContextOnceSolutionFullyLoadedAsync(cancellationToken).Forget(); } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs index d092c25f0a35c..b52774a0f090e 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs @@ -3,12 +3,13 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.Composition; using System.IO; using System.Linq; -using System.Threading.Tasks; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -17,11 +18,9 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -34,7 +33,7 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IOpenText private readonly OpenTextBufferProvider _openTextBufferProvider; private readonly IMetadataAsSourceFileService _fileTrackingMetadataAsSourceService; - private readonly Dictionary _languageInformationByLanguageGuid = []; + private readonly ConcurrentDictionary _languageInformationByLanguageGuid = []; /// /// instances for all open buffers being tracked by by this object @@ -50,8 +49,6 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IOpenText private readonly ImmutableArray _metadataReferences; - private IVsTextManager? _textManager; - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public MiscellaneousFilesWorkspace( @@ -72,11 +69,6 @@ public MiscellaneousFilesWorkspace( _openTextBufferProvider.AddListener(this); } - public async Task InitializeAsync() - { - _textManager = await _textManagerService.GetValueAsync().ConfigureAwait(false); - } - void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy? _) => TrackOpenedDocument(moniker, textBuffer); void IOpenTextBufferEventListener.OnCloseDocument(string moniker) => TryUntrackClosingDocument(moniker); @@ -115,9 +107,12 @@ public void RegisterLanguage(Guid languageGuid, string languageName, string scri private LanguageInformation? TryGetLanguageInformation(string filename) { + _threadingContext.ThrowIfNotOnUIThread(); + LanguageInformation? languageInformation = null; - if (_textManager != null && ErrorHandler.Succeeded(_textManager.MapFilenameToLanguageSID(filename, out var fileLanguageGuid))) + var textManager = _threadingContext.JoinableTaskFactory.Run(() => _textManagerService.GetValueOrNullAsync(CancellationToken.None)); + if (textManager != null && ErrorHandler.Succeeded(textManager.MapFilenameToLanguageSID(filename, out var fileLanguageGuid))) { _languageInformationByLanguageGuid.TryGetValue(fileLanguageGuid, out languageInformation); } diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index cb426a9e6681b..5ed69a6ef73da 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -165,11 +165,6 @@ private Task PackageInitializationBackgroundThreadAsync(IProgress(); - RegisterEditorFactory(settingsEditorFactory); // Proffer in-process service broker services @@ -184,12 +179,10 @@ private Task PackageInitializationBackgroundThreadAsync(IProgress ValueTaskFactory.FromResult(new ManagedEditAndContinueLanguageServiceBridge(this.ComponentModel.GetService()))); - packageRegistrationTasks.AddTask( - isMainThreadTask: false, - task: async (progress, packageRegistrationTasks, cancellationToken) => - { - await miscellaneousFilesWorkspace.InitializeAsync().ConfigureAwait(false); - }); + // Misc workspace has to be up and running by the time our package is usable so that it can track running + // doc events and appropriately map files to/from it and other relevant workspaces (like the + // metadata-as-source workspace). + var miscellaneousFilesWorkspace = this.ComponentModel.GetService(); }); return Task.CompletedTask;