/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.cs
177 строк
8 KB
Jason Malinowski
Simplify creating the COM Aggregate for our language service
29 авг 2025, 00:35
29 авг 2025, 00:35
b5b9cbe
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.Editor; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Outlining; using Microsoft.VisualStudio.TextManager.Interop; using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService; internal abstract partial class AbstractLanguageService<TPackage, TLanguageService> : AbstractLanguageService where TPackage : AbstractPackage<TPackage, TLanguageService> where TLanguageService : AbstractLanguageService<TPackage, TLanguageService> { internal TPackage Package { get; } private readonly Lazy<VsLanguageDebugInfo> _languageDebugInfo; internal readonly Lazy<VisualStudioWorkspaceImpl> Workspace; protected abstract string ContentTypeName { get; } protected abstract string LanguageName { get; } protected abstract string RoslynLanguageName { get; } protected abstract Guid DebuggerLanguageId { get; } protected AbstractLanguageService(TPackage package) { Package = package; Debug.Assert(!this.Package.JoinableTaskFactory.Context.IsOnMainThread, "Language service should be instantiated on background thread"); this.Workspace = this.Package.ComponentModel.DefaultExportProvider.GetExport<VisualStudioWorkspaceImpl>(); this._languageDebugInfo = new Lazy<VsLanguageDebugInfo>(CreateLanguageDebugInfo); } private IThreadingContext ThreadingContext => this.Package.ComponentModel.GetService<IThreadingContext>(); public override IServiceProvider SystemServiceProvider => Package; public void Setup(CancellationToken cancellationToken) { // Start off a background task to prime some components we'll need for editing. Task.Run(() => { var formatter = this.Workspace.Value.Services.GetLanguageServices(RoslynLanguageName).GetService<ISyntaxFormattingService>(); formatter?.GetDefaultFormattingRules(); }, cancellationToken).Forget(); } protected virtual void SetupNewTextView(IVsTextView textView) { Contract.ThrowIfNull(textView); var editorAdaptersFactoryService = this.Package.ComponentModel.GetService<IVsEditorAdaptersFactoryService>(); var wpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView); Contract.ThrowIfNull(wpfTextView, "Could not get IWpfTextView for IVsTextView"); Debug.Assert(!wpfTextView.Properties.ContainsProperty(typeof(AbstractVsTextViewFilter))); // The lifetime of CommandFilter is married to the view wpfTextView.GetOrCreateAutoClosingProperty(v => new StandaloneCommandFilter( v, Package.ComponentModel).AttachToVsTextView()); var isMetadataAsSource = false; var collapseAllImplementations = false; var openDocument = wpfTextView.TextBuffer.AsTextContainer().GetRelatedDocuments().FirstOrDefault(); if (openDocument?.Project.Solution.Workspace is MetadataAsSourceWorkspace masWorkspace) { isMetadataAsSource = true; // If the file is metadata as source, and the user has the preference set to collapse them, then // always collapse all metadata as source var globalOptions = this.Package.ComponentModel.GetService<IGlobalOptionService>(); var options = BlockStructureOptionsStorage.GetBlockStructureOptions(globalOptions, openDocument.Project.Language, isMetadataAsSource: true); collapseAllImplementations = masWorkspace.FileService.ShouldCollapseOnOpen(openDocument.FilePath, options); } ConditionallyCollapseOutliningRegions(textView, wpfTextView, collapseAllImplementations); // If this is a metadata-to-source view, we want to consider the file read-only and prevent // it from being re-opened when VS is opened if (isMetadataAsSource && ErrorHandler.Succeeded(textView.GetBuffer(out var vsTextLines))) { Contract.ThrowIfNull(openDocument); ErrorHandler.ThrowOnFailure(vsTextLines.GetStateFlags(out var flags)); flags |= (int)BUFFERSTATEFLAGS.BSF_USER_READONLY; ErrorHandler.ThrowOnFailure(vsTextLines.SetStateFlags(flags)); var runningDocumentTable = (IVsRunningDocumentTable)SystemServiceProvider.GetService(typeof(SVsRunningDocumentTable)); var runningDocumentTable4 = (IVsRunningDocumentTable4)runningDocumentTable; if (runningDocumentTable4.IsMonikerValid(openDocument.FilePath)) { var cookie = runningDocumentTable4.GetDocumentCookie(openDocument.FilePath); runningDocumentTable.ModifyDocumentFlags(cookie, (uint)_VSRDTFLAGS.RDT_DontAddToMRU | (uint)_VSRDTFLAGS.RDT_CantSave | (uint)_VSRDTFLAGS.RDT_DontAutoOpen, fSet: 1); } } } private void ConditionallyCollapseOutliningRegions(IVsTextView textView, IWpfTextView wpfTextView, bool collapseAllImplementations) { var outliningManagerService = this.Package.ComponentModel.GetService<IOutliningManagerService>(); var outliningManager = outliningManagerService.GetOutliningManager(wpfTextView); if (outliningManager == null) return; if (textView is IVsTextViewEx viewEx) { if (collapseAllImplementations) { // If this file is a metadata-from-source file, we want to force-collapse any implementations // to keep the display clean and condensed. outliningManager.CollapseAll(wpfTextView.TextBuffer.CurrentSnapshot.GetFullSpan(), c => c.Tag.IsImplementation); } else { // Otherwise, attempt to persist any outlining state we have computed. This // ensures that any new opened files that have any IsDefaultCollapsed spans // will both have them collapsed and remembered in the SUO file. // NOTE: Despite its name, this call will LOAD the state from the SUO file, // or collapse to definitions if it can't do that. viewEx.PersistOutliningState(); } } } private VsLanguageDebugInfo CreateLanguageDebugInfo() { var languageServices = this.Workspace.Value.Services.GetLanguageServices(RoslynLanguageName); return new VsLanguageDebugInfo( this.DebuggerLanguageId, (TLanguageService)this, languageServices, this.Package.ComponentModel.GetService<IUIThreadOperationExecutor>()); } protected virtual IVsContainedLanguage CreateContainedLanguage( IVsTextBufferCoordinator bufferCoordinator, ProjectSystemProject project, IVsHierarchy hierarchy, uint itemid) { return new ContainedLanguage( bufferCoordinator, this.Package.ComponentModel, this.Workspace.Value, project.Id, project, this.LanguageServiceId); } }