From 6a047edfe772d745407d102e8bd00b6a86ec340c Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 2 May 2022 13:41:27 -0700 Subject: [PATCH] Emulate editorconfig options for Razor design-time document, remove RazorDocumentOptionsProvider --- .../LegacyGlobalOptionsWorkspaceService.cs | 7 ++ .../RazorDocumentOptionsProviderFactory.cs | 75 ------------------- .../ILegacyGlobalOptionsWorkspaceService.cs | 3 + .../Host/DocumentService/Extensions.cs | 5 +- .../Workspace/Solution/ProjectState.cs | 52 ++++++++++++- 5 files changed, 65 insertions(+), 77 deletions(-) delete mode 100644 src/Features/Core/Portable/ExternalAccess/Razor/Api/RazorDocumentOptionsProviderFactory.cs diff --git a/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs b/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs index c51e3a6f6fc16..2b63d91443dbb 100644 --- a/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs +++ b/src/EditorFeatures/Core/Options/LegacyGlobalOptionsWorkspaceService.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Options @@ -22,5 +23,11 @@ public LegacyGlobalOptionsWorkspaceService(IGlobalOptionService globalOptions) { GlobalOptions = globalOptions; } + + public bool RazorUseTabs + => GlobalOptions.GetOption(RazorLineFormattingOptionsStorage.UseTabs); + + public int RazorTabSize + => GlobalOptions.GetOption(RazorLineFormattingOptionsStorage.TabSize); } } diff --git a/src/Features/Core/Portable/ExternalAccess/Razor/Api/RazorDocumentOptionsProviderFactory.cs b/src/Features/Core/Portable/ExternalAccess/Razor/Api/RazorDocumentOptionsProviderFactory.cs deleted file mode 100644 index 87a01af6e36db..0000000000000 --- a/src/Features/Core/Portable/ExternalAccess/Razor/Api/RazorDocumentOptionsProviderFactory.cs +++ /dev/null @@ -1,75 +0,0 @@ -// 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.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Api -{ - [Shared] - [Export(typeof(IDocumentOptionsProviderFactory))] - [ExtensionOrder(Before = PredefinedDocumentOptionsProviderNames.EditorConfig)] - internal sealed class RazorDocumentOptionsProviderFactory : IDocumentOptionsProviderFactory - { - private readonly Lazy _innerRazorDocumentOptionsService; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RazorDocumentOptionsProviderFactory( - Lazy innerRazorDocumentOptionsService) - { - if (innerRazorDocumentOptionsService is null) - { - throw new ArgumentNullException(nameof(innerRazorDocumentOptionsService)); - } - - _innerRazorDocumentOptionsService = innerRazorDocumentOptionsService; - } - - public IDocumentOptionsProvider? TryCreate(Workspace workspace) - => new RazorDocumentOptionsProvider(_innerRazorDocumentOptionsService); - - private sealed class RazorDocumentOptionsProvider : IDocumentOptionsProvider - { - public readonly Lazy RazorDocumentOptionsService; - - public RazorDocumentOptionsProvider(Lazy razorDocumentOptionsService) - { - RazorDocumentOptionsService = razorDocumentOptionsService; - } - - public async Task GetOptionsForDocumentAsync( - Document document, - CancellationToken cancellationToken) - { - if (!document.IsRazorDocument()) - { - return null; - } - - var options = await RazorDocumentOptionsService.Value.GetOptionsForDocumentAsync( - document, cancellationToken).ConfigureAwait(false); - return new RazorDocumentOptions(options); - } - } - - // Used to convert IRazorDocumentOptions -> IDocumentOptions - private sealed class RazorDocumentOptions : IDocumentOptions - { - private readonly IRazorDocumentOptions _razorOptions; - - public RazorDocumentOptions(IRazorDocumentOptions razorOptions) - { - _razorOptions = razorOptions; - } - - public bool TryGetDocumentOption(OptionKey option, out object? value) - => _razorOptions.TryGetDocumentOption(option, out value); - } - } -} diff --git a/src/Workspaces/Core/Portable/Options/ILegacyGlobalOptionsWorkspaceService.cs b/src/Workspaces/Core/Portable/Options/ILegacyGlobalOptionsWorkspaceService.cs index 28ef99b1777dc..09e25ff7610f1 100644 --- a/src/Workspaces/Core/Portable/Options/ILegacyGlobalOptionsWorkspaceService.cs +++ b/src/Workspaces/Core/Portable/Options/ILegacyGlobalOptionsWorkspaceService.cs @@ -13,5 +13,8 @@ namespace Microsoft.CodeAnalysis.Options internal interface ILegacyGlobalOptionsWorkspaceService : IWorkspaceService { public IGlobalOptionService GlobalOptions { get; } + + public bool RazorUseTabs { get; } + public int RazorTabSize { get; } } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs index f28f82c91a99c..3cbe507135a15 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/DocumentService/Extensions.cs @@ -23,6 +23,9 @@ public static bool SupportsDiagnostics([NotNullWhen(returnValue: true)] this Tex => document?.Services.GetService()?.SupportDiagnostics ?? false; public static bool IsRazorDocument(this TextDocument document) - => document.Services.GetService()?.DiagnosticsLspClientName == RazorCSharp; + => IsRazorDocument(document.State); + + public static bool IsRazorDocument(this TextDocumentState documentState) + => documentState.Services.GetService()?.DiagnosticsLspClientName == RazorCSharp; } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index d36dd5f83160d..1cb8856d561ea 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; @@ -292,6 +293,7 @@ public async Task> GetAnalyzerOptionsForPath internal sealed class ProjectAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider { private readonly ProjectState _projectState; + private RazorDesignTimeAnalyzerConfigOptions? _lazyRazorDesignTimeOptions; public ProjectAnalyzerConfigOptionsProvider(ProjectState projectState) => _projectState = projectState; @@ -300,7 +302,17 @@ public override AnalyzerConfigOptions GlobalOptions => GetOptionsForSourcePath(string.Empty); public override AnalyzerConfigOptions GetOptions(SyntaxTree tree) - => GetOptionsForSourcePath(tree.FilePath); + { + var documentId = DocumentState.GetDocumentIdForTree(tree); + if (documentId != null && + _projectState.DocumentStates.TryGetState(documentId, out var documentState) && + documentState.IsRazorDocument()) + { + _lazyRazorDesignTimeOptions ??= new RazorDesignTimeAnalyzerConfigOptions(_projectState.LanguageServices.WorkspaceServices); + } + + return GetOptionsForSourcePath(tree.FilePath); + } public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) { @@ -312,6 +324,44 @@ public AnalyzerConfigOptions GetOptionsForSourcePath(string path) => new DictionaryAnalyzerConfigOptions(_projectState._lazyAnalyzerConfigOptions.GetValue(CancellationToken.None).GetOptionsForSourcePath(path).AnalyzerOptions); } + /// + /// Provides editorconfig options for Razor design-time documents. + /// Razor does not support editorconfig options but has custom settings for a few formatting options whose values + /// are only available in-proc and the same for all Razor design-time documents. + /// This type emulates these options as analyzer config options. + /// + private sealed class RazorDesignTimeAnalyzerConfigOptions : AnalyzerConfigOptions + { + private readonly ILegacyGlobalOptionsWorkspaceService? _globalOptions; + + public RazorDesignTimeAnalyzerConfigOptions(HostWorkspaceServices services) + { + // not available OOP: + _globalOptions = services.GetService()); + } + + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + { + if (_globalOptions != null) + { + if (key == "indent_style") + { + value = _globalOptions.RazorUseTabs ? "tab" : "space"; + return true; + } + + if (key == "tab_width" || key == "indent_size") + { + value = _globalOptions.RazorTabSize.ToString(); + return true; + } + } + + value = null; + return false; + } + } + private sealed class ProjectSyntaxTreeOptionsProvider : SyntaxTreeOptionsProvider { private readonly ValueSource _lazyAnalyzerConfigSet;