From 0331efe07de5a6f2b07e82307b31359db3e81ecf Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 15 Jul 2022 13:03:20 -0700 Subject: [PATCH 1/2] Generalize RoamingProfileStorageLocation to ClientSettingsStorageLocation that can be used to access VS Settings storage regardless of whether the option roams or not. Replace LanguageSettingsPersister with LocalClientSettingsStorageLocation (subclass of ClientSettingsStorageLocation that does not roam). --- .../AbstractSignatureHelpCommandHandler.cs | 2 +- .../Core/Options/NavigationBarViewOptions.cs | 20 -- .../NavigationBarViewOptionsStorage.cs | 15 + .../Core/Options/SignatureHelpViewOptions.cs | 20 -- .../SignatureHelpViewOptionsStorage.cs | 15 + .../CSharpSignatureHelpCommandHandlerTests.vb | 2 +- ...alBasicSignatureHelpCommandHandlerTests.vb | 2 +- ...IncrementalAnalyzer_IncrementalAnalyzer.cs | 2 +- .../Options/CompletionOptionsStorage.cs | 10 +- .../Options/DiagnosticModeExtensions.cs | 2 +- .../Options/DiagnosticOptionsStorage.cs} | 2 +- .../Options/FeatureFlagStorageLocation.cs | 0 .../Diagnostics/PullDiagnosticTests.cs | 4 +- .../Options/AdvancedOptionPageControl.xaml.cs | 2 +- ...ctLanguageService`2.VsCodeWindowManager.cs | 4 +- .../Def/Options/LanguageSettingsPersister.cs | 278 ------------------ .../LanguageSettingsPersisterProvider.cs | 66 ----- ...=> VisualStudioSettingsOptionPersister.cs} | 33 +-- ...lStudioSettingsOptionPersisterProvider.cs} | 8 +- .../VisualStudioWorkspaceImpl.cs | 2 +- .../VisualStudioWorkspaceTelemetryService.cs | 2 +- .../CSharp/CSharpNavigationBar.cs | 4 +- .../InProcess/StateResetInProcess.cs | 2 +- .../VisualBasic/BasicNavigationBar.cs | 4 +- .../Core/CompilerExtensions.projitems | 3 +- .../Core/Formatting/FormattingOptions2.cs | 17 +- .../Options/ClientSettingsStorageLocation.cs | 44 +++ .../LocalClientSettingsStorageLocation.cs | 35 +++ .../LocalUserProfileStorageLocation.cs | 2 +- .../Options/RoamingProfileStorageLocation.cs | 49 ++- 30 files changed, 181 insertions(+), 470 deletions(-) delete mode 100644 src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs create mode 100644 src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs delete mode 100644 src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs create mode 100644 src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs rename src/Features/{Core/Portable/Diagnostics/DiagnosticOptions.cs => LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs} (95%) rename src/{Workspaces/SharedUtilitiesAndExtensions/Compiler/Core => Features/LanguageServer/Protocol/Features}/Options/FeatureFlagStorageLocation.cs (100%) delete mode 100644 src/VisualStudio/Core/Def/Options/LanguageSettingsPersister.cs delete mode 100644 src/VisualStudio/Core/Def/Options/LanguageSettingsPersisterProvider.cs rename src/VisualStudio/Core/Def/Options/{RoamingVisualStudioProfileOptionPersister.cs => VisualStudioSettingsOptionPersister.cs} (88%) rename src/VisualStudio/Core/Def/Options/{RoamingVisualStudioProfileOptionPersisterProvider.cs => VisualStudioSettingsOptionPersisterProvider.cs} (83%) create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs index f854ed36aa280..8106e43c6597b 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs @@ -40,7 +40,7 @@ protected bool TryGetController(EditorCommandArgs args, out Controller controlle var languageName = args.SubjectBuffer.GetLanguageName(); if (args is not InvokeSignatureHelpCommandArgs && languageName != null && - !_globalOptions.GetOption(SignatureHelpViewOptions.ShowSignatureHelp, languageName)) + !_globalOptions.GetOption(SignatureHelpViewOptionsStorage.ShowSignatureHelp, languageName)) { controller = null; return false; diff --git a/src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs b/src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs deleted file mode 100644 index cde4d9cbf4e2e..0000000000000 --- a/src/EditorFeatures/Core/Options/NavigationBarViewOptions.cs +++ /dev/null @@ -1,20 +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.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Editor.Options -{ - internal sealed class NavigationBarViewOptions - { - private const string FeatureName = "NavigationBarOptions"; - - public static readonly PerLanguageOption2 ShowNavigationBar = new(FeatureName, "ShowNavigationBar", defaultValue: true); - } -} diff --git a/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs new file mode 100644 index 0000000000000..1d7ec8496b7ff --- /dev/null +++ b/src/EditorFeatures/Core/Options/NavigationBarViewOptionsStorage.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.Options; + +internal sealed class NavigationBarViewOptionsStorage +{ + private const string FeatureName = "NavigationBarOptions"; + + public static readonly PerLanguageOption2 ShowNavigationBar = new( + FeatureName, "ShowNavigationBar", defaultValue: true, new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Dropdown Bar")); +} diff --git a/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs b/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs deleted file mode 100644 index 0383174fb5338..0000000000000 --- a/src/EditorFeatures/Core/Options/SignatureHelpViewOptions.cs +++ /dev/null @@ -1,20 +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.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Editor.Options -{ - internal sealed class SignatureHelpViewOptions - { - private const string FeatureName = "SignatureHelpOptions"; - - public static readonly PerLanguageOption2 ShowSignatureHelp = new(FeatureName, nameof(ShowSignatureHelp), defaultValue: true); - } -} diff --git a/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs new file mode 100644 index 0000000000000..3d02f2959d98e --- /dev/null +++ b/src/EditorFeatures/Core/Options/SignatureHelpViewOptionsStorage.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.Options; + +internal sealed class SignatureHelpViewOptionsStorage +{ + private const string FeatureName = "SignatureHelpOptions"; + + public static readonly PerLanguageOption2 ShowSignatureHelp = new( + FeatureName, "ShowSignatureHelp", defaultValue: true, new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Auto List Params")); +} diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb index 7e4556adaff71..98422df0558b6 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpSignatureHelpCommandHandlerTests.vb @@ -884,7 +884,7 @@ class C , showCompletionInArgumentLists:=showCompletionInArgumentLists) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptions.ShowSignatureHelp, LanguageNames.CSharp), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.CSharp), False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb index 0257bc75979e0..cbe2eaeb82cd0 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicSignatureHelpCommandHandlerTests.vb @@ -283,7 +283,7 @@ End Class ) ' disable implicit sig help then type a trigger character -> no session should be available - state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptions.ShowSignatureHelp, LanguageNames.VisualBasic), False) + state.Workspace.GetService(Of IGlobalOptionService).SetGlobalOption(New OptionKey(SignatureHelpViewOptionsStorage.ShowSignatureHelp, LanguageNames.VisualBasic), False) state.SendTypeChars("(") Await state.AssertNoSignatureHelpSession() diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 580473cd337ed..5692075529be5 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -90,7 +90,7 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi { var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind); var executor = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException); - var logTelemetry = GlobalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); + var logTelemetry = GlobalOptions.GetOption(DiagnosticOptionsStorage.LogTelemetryForBackgroundAnalyzerExecution); foreach (var stateSet in nonCachedStateSets) { var computedData = await ComputeDocumentAnalysisDataAsync(executor, stateSet, logTelemetry, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs index 8f88c40e10cba..725dda47f9acd 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CompletionOptionsStorage.cs @@ -47,11 +47,13 @@ public static CompletionOptions GetCompletionOptions(this IGlobalOptionService o CompletionOptions.Default.SnippetCompletion, new FeatureFlagStorageLocation("Roslyn.SnippetCompletion")); - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 HideAdvancedMembers = new(nameof(CompletionOptions), nameof(HideAdvancedMembers), CompletionOptions.Default.HideAdvancedMembers); + public static readonly PerLanguageOption2 HideAdvancedMembers = new( + "CompletionOptions", "HideAdvancedMembers", CompletionOptions.Default.HideAdvancedMembers, + new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Hide Advanced Auto List Members")); - // This is serialized by the Visual Studio-specific LanguageSettingsPersister - public static readonly PerLanguageOption2 TriggerOnTyping = new(nameof(CompletionOptions), nameof(TriggerOnTyping), CompletionOptions.Default.TriggerOnTyping); + public static readonly PerLanguageOption2 TriggerOnTyping = new( + "CompletionOptions", "TriggerOnTyping", CompletionOptions.Default.TriggerOnTyping, + new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Auto List Members")); public static readonly PerLanguageOption2 TriggerOnTypingLetters = new(nameof(CompletionOptions), nameof(TriggerOnTypingLetters), CompletionOptions.Default.TriggerOnTypingLetters, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.TriggerOnTypingLetters")); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs index 1a5ef527389ae..e3f727145d68f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticModeExtensions.cs @@ -16,7 +16,7 @@ public static DiagnosticMode GetDiagnosticMode(this IGlobalOptionService globalO // If the workspace diagnostic mode is set to Default, defer to the feature flag service. if (diagnosticModeOption == DiagnosticMode.Default) { - return globalOptions.GetOption(DiagnosticOptions.LspPullDiagnosticsFeatureFlag) ? DiagnosticMode.Pull : DiagnosticMode.Push; + return globalOptions.GetOption(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag) ? DiagnosticMode.Pull : DiagnosticMode.Push; } // Otherwise, defer to the workspace+option to determine what mode we're in. diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs similarity index 95% rename from src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs rename to src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs index 1422e927ed734..506fbce515ed9 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticOptions.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/DiagnosticOptionsStorage.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics { - internal sealed class DiagnosticOptions + internal sealed class DiagnosticOptionsStorage { private const string FeatureName = "DiagnosticOptions"; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/FeatureFlagStorageLocation.cs b/src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/FeatureFlagStorageLocation.cs rename to src/Features/LanguageServer/Protocol/Features/Options/FeatureFlagStorageLocation.cs diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 4669c384bf3b3..330cf0445e184 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -99,7 +99,7 @@ public async Task TestNoDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOf await OpenDocumentAsync(testLspServer, document); // Ensure we get no diagnostics when feature flag is off. - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptions.LspPullDiagnosticsFeatureFlag), false); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), false); await Assert.ThrowsAsync(async () => await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics)); } @@ -117,7 +117,7 @@ public async Task TestDocumentDiagnosticsForOpenFilesIfDefaultAndFeatureFlagOn(b var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); await OpenDocumentAsync(testLspServer, document); - testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptions.LspPullDiagnosticsFeatureFlag), true); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag), true); var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics); Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 276ea9e1fb086..69ea931e44093 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -229,7 +229,7 @@ private void Enable_pull_diagnostics_experimental_requires_restart_CheckedChange if (checkboxValue != null) { // Update the actual value of the feature flag to ensure CPS is informed of the new feature flag value. - this.OptionStore.SetOption(DiagnosticOptions.LspPullDiagnosticsFeatureFlag, checkboxValue.Value); + this.OptionStore.SetOption(DiagnosticOptionsStorage.LspPullDiagnosticsFeatureFlag, checkboxValue.Value); } // Update the workspace option. diff --git a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs index e1daa6d2474fe..c4c33af48d2fd 100644 --- a/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs +++ b/src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsCodeWindowManager.cs @@ -51,7 +51,7 @@ private void SetupView(IVsTextView view) private void GlobalOptionChanged(object sender, OptionChangedEventArgs e) { if (e.Language != _languageService.RoslynLanguageName || - e.Option != NavigationBarViewOptions.ShowNavigationBar) + e.Option != NavigationBarViewOptionsStorage.ShowNavigationBar) { return; } @@ -87,7 +87,7 @@ private void AddOrRemoveDropdown() return; } - var enabled = _globalOptions.GetOption(NavigationBarViewOptions.ShowNavigationBar, _languageService.RoslynLanguageName); + var enabled = _globalOptions.GetOption(NavigationBarViewOptionsStorage.ShowNavigationBar, _languageService.RoslynLanguageName); if (enabled) { if (IsOurDropdownBar(dropdownManager, out var existingDropdownBar)) diff --git a/src/VisualStudio/Core/Def/Options/LanguageSettingsPersister.cs b/src/VisualStudio/Core/Def/Options/LanguageSettingsPersister.cs deleted file mode 100644 index 2d46f1c5ecc3e..0000000000000 --- a/src/VisualStudio/Core/Def/Options/LanguageSettingsPersister.cs +++ /dev/null @@ -1,278 +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. - -#nullable disable - -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Editor.Options; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.LanguageServices.Setup; -using Microsoft.VisualStudio.TextManager.Interop; -using Roslyn.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options -{ - /// - /// An that syncs core language settings against the settings that exist for all languages - /// in Visual Studio and whose backing store is provided by the shell. This includes things like default tab size, tabs vs. spaces, etc. - /// - /// TODO: replace with free-threaded impl: https://github.com/dotnet/roslyn/issues/56815 - /// - internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObject, IVsTextManagerEvents4, IOptionPersister - { - private readonly IVsTextManager4 _textManager; - private readonly IGlobalOptionService _globalOptions; - -#pragma warning disable IDE0052 // Remove unread private members - https://github.com/dotnet/roslyn/issues/46167 - private readonly ComEventSink _textManagerEvents2Sink; -#pragma warning restore IDE0052 // Remove unread private members - - /// - /// The mapping between language names and Visual Studio language service GUIDs. - /// - /// - /// This is a map between string and rather than just to - /// to avoid a bunch of JIT during startup. Generics of value types like will have to JIT - /// but the ngen image will exist for the basic map between two reference types, since those are reused. - private readonly IBidirectionalMap> _languageMap; - - /// - /// We make sure this code is from the UI by asking for all in - /// - public LanguageSettingsPersister( - IThreadingContext threadingContext, - IVsTextManager4 textManager, - IGlobalOptionService globalOptions) - : base(threadingContext, assertIsForeground: true) - { - _textManager = textManager; - _globalOptions = globalOptions; - - var languageMap = BidirectionalMap>.Empty; - - InitializeSettingsForLanguage(LanguageNames.CSharp, Guids.CSharpLanguageServiceId); - InitializeSettingsForLanguage(LanguageNames.VisualBasic, Guids.VisualBasicLanguageServiceId); - InitializeSettingsForLanguage(InternalLanguageNames.TypeScript, new Guid("4a0dddb5-7a95-4fbf-97cc-616d07737a77")); - InitializeSettingsForLanguage("F#", new Guid("BC6DD5A5-D4D6-4dab-A00D-A51242DBAF1B")); - InitializeSettingsForLanguage("Xaml", new Guid("CD53C9A1-6BC2-412B-BE36-CC715ED8DD41")); - - void InitializeSettingsForLanguage(string languageName, Guid languageGuid) - { - var languagePreferences = new LANGPREFERENCES3[1]; - languagePreferences[0].guidLang = languageGuid; - - // The function can potentially fail if that language service isn't installed - if (ErrorHandler.Succeeded(_textManager.GetUserPreferences4(pViewPrefs: null, pLangPrefs: languagePreferences, pColorPrefs: null))) - { - RefreshLanguageSettings(languagePreferences, languageName); - languageMap = languageMap.Add(languageName, Tuple.Create(languageGuid)); - } - else - { - FatalError.ReportWithDumpAndCatch(new InvalidOperationException("GetUserPreferences4 failed"), ErrorSeverity.Diagnostic); - } - } - - _languageMap = languageMap; - _textManagerEvents2Sink = ComEventSink.Advise(_textManager, this); - } - - private readonly IOption[] _supportedOptions = new IOption[] - { - FormattingOptions.UseTabs, - FormattingOptions.TabSize, - FormattingOptions.SmartIndent, - FormattingOptions.IndentationSize, - CompletionOptionsStorage.HideAdvancedMembers, - CompletionOptionsStorage.TriggerOnTyping, - SignatureHelpViewOptions.ShowSignatureHelp, - NavigationBarViewOptions.ShowNavigationBar - }; - - int IVsTextManagerEvents4.OnUserPreferencesChanged4( - VIEWPREFERENCES3[] viewPrefs, - LANGPREFERENCES3[] langPrefs, - FONTCOLORPREFERENCES2[] colorPrefs) - { - if (langPrefs != null) - { - RefreshLanguageSettings(langPrefs); - } - - return VSConstants.S_OK; - } - - private void RefreshLanguageSettings(LANGPREFERENCES3[] langPrefs) - { - this.AssertIsForeground(); - if (_languageMap.TryGetKey(Tuple.Create(langPrefs[0].guidLang), out var languageName)) - { - RefreshLanguageSettings(langPrefs, languageName); - } - } - - private void RefreshLanguageSettings(LANGPREFERENCES3[] langPrefs, string languageName) - { - this.AssertIsForeground(); - - foreach (var option in _supportedOptions) - { - var keyWithLanguage = new OptionKey(option, languageName); - var newValue = GetValueForOption(option, langPrefs[0]); - - _globalOptions.RefreshOption(keyWithLanguage, newValue); - } - } - - private static object GetValueForOption(IOption option, LANGPREFERENCES3 languagePreference) - { - if (option == FormattingOptions.UseTabs) - { - return languagePreference.fInsertTabs != 0; - } - else if (option == FormattingOptions.TabSize) - { - return Convert.ToInt32(languagePreference.uTabSize); - } - else if (option == FormattingOptions.IndentationSize) - { - return Convert.ToInt32(languagePreference.uIndentSize); - } - else if (option == FormattingOptions.SmartIndent) - { - switch (languagePreference.IndentStyle) - { - case vsIndentStyle.vsIndentStyleNone: - return FormattingOptions.IndentStyle.None; - case vsIndentStyle.vsIndentStyleDefault: - return FormattingOptions.IndentStyle.Block; - default: - return FormattingOptions.IndentStyle.Smart; - } - } - else if (option == CompletionOptionsStorage.HideAdvancedMembers) - { - return languagePreference.fHideAdvancedAutoListMembers != 0; - } - else if (option == CompletionOptionsStorage.TriggerOnTyping) - { - return languagePreference.fAutoListMembers != 0; - } - else if (option == SignatureHelpViewOptions.ShowSignatureHelp) - { - return languagePreference.fAutoListParams != 0; - } - else if (option == NavigationBarViewOptions.ShowNavigationBar) - { - return languagePreference.fDropdownBar != 0; - } - else - { - throw new ArgumentException("Unexpected option.", nameof(option)); - } - } - - private static void SetValueForOption(IOption option, ref LANGPREFERENCES3 languagePreference, object value) - { - if (option == FormattingOptions.UseTabs) - { - languagePreference.fInsertTabs = Convert.ToUInt32((bool)value ? 1 : 0); - } - else if (option == FormattingOptions.TabSize) - { - languagePreference.uTabSize = Convert.ToUInt32(value); - } - else if (option == FormattingOptions.IndentationSize) - { - languagePreference.uIndentSize = Convert.ToUInt32(value); - } - else if (option == FormattingOptions.SmartIndent) - { - switch ((FormattingOptions.IndentStyle)value) - { - case FormattingOptions.IndentStyle.None: - languagePreference.IndentStyle = vsIndentStyle.vsIndentStyleNone; - break; - case FormattingOptions.IndentStyle.Block: - languagePreference.IndentStyle = vsIndentStyle.vsIndentStyleDefault; - break; - default: - languagePreference.IndentStyle = vsIndentStyle.vsIndentStyleSmart; - break; - } - } - else if (option == CompletionOptionsStorage.HideAdvancedMembers) - { - languagePreference.fHideAdvancedAutoListMembers = Convert.ToUInt32((bool)value ? 1 : 0); - } - else if (option == CompletionOptionsStorage.TriggerOnTyping) - { - languagePreference.fAutoListMembers = Convert.ToUInt32((bool)value ? 1 : 0); - } - else if (option == SignatureHelpViewOptions.ShowSignatureHelp) - { - languagePreference.fAutoListParams = Convert.ToUInt32((bool)value ? 1 : 0); - } - else if (option == NavigationBarViewOptions.ShowNavigationBar) - { - languagePreference.fDropdownBar = Convert.ToUInt32((bool)value ? 1 : 0); - } - else - { - throw new ArgumentException("Unexpected option.", nameof(option)); - } - } - - public bool TryFetch(OptionKey optionKey, out object value) - { - // This particular serializer is a bit strange, since we have to initially read things out on the UI thread. - // Therefore, we refresh the values in the constructor, meaning that this should never get called for our values. - - if (_supportedOptions.Contains(optionKey.Option) && _languageMap.ContainsKey(optionKey.Language)) - { - FatalError.ReportWithDumpAndCatch(new InvalidOperationException("Unexpected call to " + nameof(LanguageSettingsPersister) + "." + nameof(TryFetch)), ErrorSeverity.Diagnostic); - } - - value = null; - return false; - } - - public bool TryPersist(OptionKey optionKey, object value) - { - if (!_supportedOptions.Contains(optionKey.Option)) - { - return false; - } - - if (!_languageMap.TryGetValue(optionKey.Language, out var languageServiceGuid)) - { - return false; - } - - var languagePreferences = new LANGPREFERENCES3[1]; - languagePreferences[0].guidLang = languageServiceGuid.Item1; - Marshal.ThrowExceptionForHR(_textManager.GetUserPreferences4(null, languagePreferences, null)); - - SetValueForOption(optionKey.Option, ref languagePreferences[0], value); - _ = SetUserPreferencesMaybeAsync(languagePreferences); - - // Even if we didn't call back, say we completed the persist - return true; - } - - private async Task SetUserPreferencesMaybeAsync(LANGPREFERENCES3[] languagePreferences) - { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); - Marshal.ThrowExceptionForHR(_textManager.SetUserPreferences4(pViewPrefs: null, pLangPrefs: languagePreferences, pColorPrefs: null)); - } - } -} diff --git a/src/VisualStudio/Core/Def/Options/LanguageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/LanguageSettingsPersisterProvider.cs deleted file mode 100644 index e58eedebe3818..0000000000000 --- a/src/VisualStudio/Core/Def/Options/LanguageSettingsPersisterProvider.cs +++ /dev/null @@ -1,66 +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.ComponentModel.Composition; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.TextManager.Interop; -using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; -using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options -{ - [Export(typeof(IOptionPersisterProvider))] - internal sealed class LanguageSettingsPersisterProvider : IOptionPersisterProvider - { - private readonly IThreadingContext _threadingContext; - private readonly IAsyncServiceProvider _serviceProvider; - private readonly IGlobalOptionService _optionService; - private LanguageSettingsPersister? _lazyPersister; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LanguageSettingsPersisterProvider( - IThreadingContext threadingContext, - [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, - IGlobalOptionService optionService) - { - _threadingContext = threadingContext; - _serviceProvider = serviceProvider; - _optionService = optionService; - } - - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) - { - if (_lazyPersister is not null) - { - return _lazyPersister; - } - - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - // Asynchronously load dependent package prior to calling synchronous APIs on IVsTextManager4 - _ = await _serviceProvider.GetServiceAsync(typeof(SVsManagedFontAndColorInformation)).ConfigureAwait(true); - - var textManager = (IVsTextManager4?)await _serviceProvider.GetServiceAsync(typeof(SVsTextManager)).ConfigureAwait(true); - Assumes.Present(textManager); - - _lazyPersister ??= new LanguageSettingsPersister(_threadingContext, textManager, _optionService); - return _lazyPersister; - } - - /// - /// Shim to allow asynchronous loading of a package prior to calling synchronous (blocking) APIs that use it. - /// - [Guid("48d069e8-1993-4752-baf3-232236a3ea4f")] - private class SVsManagedFontAndColorInformation - { - } - } -} diff --git a/src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersister.cs b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs similarity index 88% rename from src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersister.cs rename to src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs index 7d4eb04f6ff3c..806bc4cca84f1 100644 --- a/src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersister.cs @@ -20,9 +20,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { /// - /// Serializes settings marked with to and from the user's roaming profile. + /// Serializes settings marked with to and from VS Settings storage. /// - internal sealed class RoamingVisualStudioProfileOptionPersister : IOptionPersister + internal sealed class VisualStudioSettingsOptionPersister : IOptionPersister { // NOTE: This service is not public or intended for use by teams/individuals outside of Microsoft. Any data stored is subject to deletion without warning. [Guid("9B164E40-C3A2-4363-9BC5-EB4039DEF653")] @@ -42,7 +42,7 @@ private class SVsSettingsPersistenceManager { }; /// /// We make sure this code is from the UI by asking for all in /// - public RoamingVisualStudioProfileOptionPersister(IGlobalOptionService globalOptionService, ISettingsManager? settingsManager) + public VisualStudioSettingsOptionPersister(IGlobalOptionService globalOptionService, ISettingsManager? settingsManager) { Contract.ThrowIfNull(globalOptionService); @@ -91,21 +91,21 @@ private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, Propert return System.Threading.Tasks.Task.CompletedTask; } - private object? GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable roamingSerializations) + private object? GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable storageLocations) { Contract.ThrowIfNull(_settingManager); - // There can be more than 1 roaming location in the order of their priority. + // There can be more than 1 storage location in the order of their priority. // When fetching a value, we iterate all of them until we find the first one that exists. // When persisting a value, we always use the first location. - // This functionality exists for breaking changes to persistence of some options. In such a case, there + // This functionality exists to accomodate breaking changes to persistence of some options. In such a case, there // will be a new location added to the beginning with a new name. When fetching a value, we might find the old // location (and can upgrade the value accordingly) but we only write to the new location so that // we don't interfere with older versions. This will essentially "fork" the user's options at the time of upgrade. - foreach (var roamingSerialization in roamingSerializations) + foreach (var storageLocation in storageLocations) { - var storageKey = roamingSerialization.GetKeyNameForLanguage(optionKey.Language); + var storageKey = storageLocation.GetKeyNameForLanguage(optionKey.Language); RecordObservedValueToWatchForChanges(optionKey, storageKey); @@ -127,16 +127,14 @@ public bool TryFetch(OptionKey optionKey, out object? value) return false; } - // Do we roam this at all? - var roamingSerializations = optionKey.Option.StorageLocations.OfType(); - - if (!roamingSerializations.Any()) + var storageLocations = optionKey.Option.StorageLocations.OfType(); + if (!storageLocations.Any()) { value = null; return false; } - value = GetFirstOrDefaultValue(optionKey, roamingSerializations); + value = GetFirstOrDefaultValue(optionKey, storageLocations); // VS's ISettingsManager has some quirks around storing enums. Specifically, // it *can* persist and retrieve enums, but only if you properly call @@ -250,14 +248,13 @@ public bool TryPersist(OptionKey optionKey, object? value) } // Do we roam this at all? - var roamingSerialization = optionKey.Option.StorageLocations.OfType().FirstOrDefault(); - - if (roamingSerialization == null) + var storageLocation = optionKey.Option.StorageLocations.OfType().FirstOrDefault(); + if (storageLocation == null) { return false; } - var storageKey = roamingSerialization.GetKeyNameForLanguage(optionKey.Language); + var storageKey = storageLocation.GetKeyNameForLanguage(optionKey.Language); RecordObservedValueToWatchForChanges(optionKey, storageKey); @@ -275,7 +272,7 @@ public bool TryPersist(OptionKey optionKey, object? value) } } - _settingManager.SetValueAsync(storageKey, value, isMachineLocal: false); + _settingManager.SetValueAsync(storageKey, value, storageLocation.IsMachineLocal); return true; } } diff --git a/src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs similarity index 83% rename from src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs rename to src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs index 21388ceaf887d..79970bbae5ce3 100644 --- a/src/VisualStudio/Core/Def/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioSettingsOptionPersisterProvider.cs @@ -17,15 +17,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { [Export(typeof(IOptionPersisterProvider))] - internal sealed class RoamingVisualStudioProfileOptionPersisterProvider : IOptionPersisterProvider + internal sealed class VisualStudioSettingsOptionPersisterProvider : IOptionPersisterProvider { private readonly IAsyncServiceProvider _serviceProvider; private readonly IGlobalOptionService _optionService; - private RoamingVisualStudioProfileOptionPersister? _lazyPersister; + private VisualStudioSettingsOptionPersister? _lazyPersister; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RoamingVisualStudioProfileOptionPersisterProvider( + public VisualStudioSettingsOptionPersisterProvider( [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, IGlobalOptionService optionService) { @@ -42,7 +42,7 @@ public async ValueTask GetOrCreatePersisterAsync(CancellationT var settingsManager = (ISettingsManager?)await _serviceProvider.GetServiceAsync(typeof(SVsSettingsPersistenceManager)).ConfigureAwait(true); - _lazyPersister ??= new RoamingVisualStudioProfileOptionPersister(_optionService, settingsManager); + _lazyPersister ??= new VisualStudioSettingsOptionPersister(_optionService, settingsManager); return _lazyPersister; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs index ce805131200d3..5246701e55e5f 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -247,7 +247,7 @@ public async Task InitializeUIAffinitizedServicesAsync(IAsyncServiceProvider asy // Switch to a background thread to avoid loading option providers on UI thread (telemetry is reading options). await TaskScheduler.Default; - var logDelta = _globalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); + var logDelta = _globalOptions.GetOption(DiagnosticOptionsStorage.LogTelemetryForBackgroundAnalyzerExecution); var telemetryService = (VisualStudioWorkspaceTelemetryService)Services.GetRequiredService(); telemetryService.InitializeTelemetrySession(telemetrySession, logDelta); diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs index d5f447dece3a1..c4a4c4a7b9410 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs @@ -57,7 +57,7 @@ protected override void TelemetrySessionInitialized() Contract.ThrowIfNull(settings); // Only log "delta" property for block end events if feature flag is enabled. - var logDelta = _globalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution); + var logDelta = _globalOptions.GetOption(DiagnosticOptionsStorage.LogTelemetryForBackgroundAnalyzerExecution); // initialize session in the remote service _ = await client.TryInvokeAsync( diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs index 7e741a5e85e0f..2bc6205268b82 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNavigationBar.cs @@ -128,10 +128,10 @@ struct S public async Task VerifyOption() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.CSharp), false); + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp), false); Assert.False(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.CSharp), true); + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.CSharp), true); Assert.True(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs index de1ca9334b525..fd70e44acec22 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs @@ -45,7 +45,7 @@ public async Task ResetGlobalOptionsAsync(CancellationToken cancellationToken) var globalOptions = await GetComponentModelServiceAsync(cancellationToken); ResetOption(globalOptions, MetadataAsSourceOptionsStorage.NavigateToDecompiledSources); ResetOption(globalOptions, WorkspaceConfigurationOptionsStorage.EnableOpeningSourceGeneratedFilesInWorkspace); - ResetPerLanguageOption(globalOptions, NavigationBarViewOptions.ShowNavigationBar); + ResetPerLanguageOption(globalOptions, NavigationBarViewOptionsStorage.ShowNavigationBar); ResetPerLanguageOption(globalOptions, VisualStudioNavigationOptions.NavigateToObjectBrowser); ResetPerLanguageOption(globalOptions, FeatureOnOffOptions.AddImportsOnPaste); ResetPerLanguageOption(globalOptions, FeatureOnOffOptions.PrettyListing); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs index 148296fa6a7b6..6b584a5795d36 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs @@ -104,10 +104,10 @@ public async Task VerifyOption() { var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.VisualBasic), false); + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic), false); Assert.False(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.VisualBasic), true); + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptionsStorage.ShowNavigationBar, LanguageNames.VisualBasic), true); Assert.True(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 485781f385fab..50b0a2f6313b7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -250,7 +250,6 @@ - @@ -390,6 +389,8 @@ + + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs index ea388ce1453e3..8de387a714922 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.cs @@ -39,20 +39,21 @@ public Provider() public static PerLanguageOption2 UseTabs = new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(UseTabs), LineFormattingOptions.Default.UseTabs, - storageLocation: new EditorConfigStorageLocation( - "indent_style", - s => s == "tab", - isSet => isSet ? "tab" : "space")); + storageLocations: ImmutableArray.Create( + new EditorConfigStorageLocation("indent_style", s => s == "tab", isSet => isSet ? "tab" : "space"), + new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Insert Tabs"))); - // This is also serialized by the Visual Studio-specific LanguageSettingsPersister public static PerLanguageOption2 TabSize = new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(TabSize), LineFormattingOptions.Default.TabSize, - storageLocation: EditorConfigStorageLocation.ForInt32Option("tab_width")); + storageLocations: ImmutableArray.Create( + EditorConfigStorageLocation.ForInt32Option("tab_width"), + new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Tab Size"))); - // This is also serialized by the Visual Studio-specific LanguageSettingsPersister public static PerLanguageOption2 IndentationSize = new(FeatureName, FormattingOptionGroups.IndentationAndSpacing, nameof(IndentationSize), LineFormattingOptions.Default.IndentationSize, - storageLocation: EditorConfigStorageLocation.ForInt32Option("indent_size")); + storageLocations: ImmutableArray.Create( + EditorConfigStorageLocation.ForInt32Option("indent_size"), + new LocalClientSettingsStorageLocation("TextEditor.%LANGUAGE%.Indent Size"))); public static PerLanguageOption2 NewLine = new(FeatureName, FormattingOptionGroups.NewLine, nameof(NewLine), LineFormattingOptions.Default.NewLine, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs new file mode 100644 index 0000000000000..10621a7c23961 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs @@ -0,0 +1,44 @@ +// 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 Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Specifies that the option is stored in setting storage of the client. +/// +/// +/// TODO (https://github.com/dotnet/roslyn/issues/62683): The options that use this storage are global client options. +/// This storage should really be in the VS layer but currently option storage is coupled with option definition and thus the storage is needed here. +/// +internal abstract class ClientSettingsStorageLocation : OptionStorageLocation2 +{ + private readonly Func _keyNameFromLanguageName; + + public ClientSettingsStorageLocation(string keyName) + => _keyNameFromLanguageName = _ => keyName; + + /// + /// Creates a that has different key names for different languages. + /// + /// A function that maps from a value to the key name. + public ClientSettingsStorageLocation(Func keyNameFromLanguageName) + => _keyNameFromLanguageName = keyNameFromLanguageName; + + public abstract bool IsMachineLocal { get; } + + public string GetKeyNameForLanguage(string? languageName) + { + var keyName = _keyNameFromLanguageName(languageName); + + if (languageName != null) + { + keyName = keyName.Replace("%LANGUAGE%", languageName switch { LanguageNames.CSharp => "CSharp", LanguageNames.VisualBasic => "VisualBasic", _ => languageName }); + } + + return keyName; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs new file mode 100644 index 0000000000000..d4cf826b9c501 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalClientSettingsStorageLocation.cs @@ -0,0 +1,35 @@ +// 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; + +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Specifies that the option should be stored into local client settings storage. +/// +/// +/// Unlike LocalUserRegistryOptionPersister, which accesses the registry directly this storage is managed by VS Settings component. +/// +/// TODO (https://github.com/dotnet/roslyn/issues/62683): The options that use this storage are global client options. This storage should really be in the VS layer but currently +/// option storage is coupled with option definition and thus the storage is needed here. +/// +internal sealed class LocalClientSettingsStorageLocation : ClientSettingsStorageLocation +{ + public override bool IsMachineLocal => true; + + public LocalClientSettingsStorageLocation(string keyName) + : base(keyName) + { + } + + /// + /// Creates a that has different key names for different languages. + /// + /// A function that maps from a value to the key name. + public LocalClientSettingsStorageLocation(Func keyNameFromLanguageName) + : base(keyNameFromLanguageName) + { + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs index 17bdc17c6fcc9..6c648abed60c4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/LocalUserProfileStorageLocation.cs @@ -5,7 +5,7 @@ namespace Microsoft.CodeAnalysis.Options { /// - /// Specifies that the option should be stored into the user's local registry hive. + /// Specifies that the option should be stored into the user's local Roslyn specific registry hive. /// internal sealed class LocalUserProfileStorageLocation : OptionStorageLocation2 { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs index 435d9ab802415..ec382f18d23df 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs @@ -4,41 +4,26 @@ using System; -namespace Microsoft.CodeAnalysis.Options +namespace Microsoft.CodeAnalysis.Options; + +/// +/// Specifies that the option should be stored into a roamed profile across machines. +/// +internal sealed class RoamingProfileStorageLocation : ClientSettingsStorageLocation { + public override bool IsMachineLocal => false; + + public RoamingProfileStorageLocation(string keyName) + : base(keyName) + { + } + /// - /// Specifies that the option should be stored into a roamed profile across machines. + /// Creates a that has different key names for different languages. /// - internal sealed class RoamingProfileStorageLocation : OptionStorageLocation2 + /// A function that maps from a value to the key name. + public RoamingProfileStorageLocation(Func keyNameFromLanguageName) + : base(keyNameFromLanguageName) { - private readonly Func _keyNameFromLanguageName; - - public string GetKeyNameForLanguage(string? languageName) - { - var unsubstitutedKeyName = _keyNameFromLanguageName(languageName); - - if (languageName == null) - { - return unsubstitutedKeyName; - } - else - { - var substituteLanguageName = languageName == LanguageNames.CSharp ? "CSharp" : - languageName == LanguageNames.VisualBasic ? "VisualBasic" : - languageName; - - return unsubstitutedKeyName.Replace("%LANGUAGE%", substituteLanguageName); - } - } - - public RoamingProfileStorageLocation(string keyName) - => _keyNameFromLanguageName = _ => keyName; - - /// - /// Creates a that has different key names for different languages. - /// - /// A function that maps from a value to the key name. - public RoamingProfileStorageLocation(Func keyNameFromLanguageName) - => _keyNameFromLanguageName = keyNameFromLanguageName; } } From c4d0f6be4a3623c3332ad8a717212b4d7fdce470 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 15 Jul 2022 17:49:43 -0700 Subject: [PATCH 2/2] Feedback --- .../Compiler/Core/Options/ClientSettingsStorageLocation.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs index 10621a7c23961..3d12ba03c3427 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/ClientSettingsStorageLocation.cs @@ -36,7 +36,12 @@ public string GetKeyNameForLanguage(string? languageName) if (languageName != null) { - keyName = keyName.Replace("%LANGUAGE%", languageName switch { LanguageNames.CSharp => "CSharp", LanguageNames.VisualBasic => "VisualBasic", _ => languageName }); + keyName = keyName.Replace("%LANGUAGE%", languageName switch + { + LanguageNames.CSharp => "CSharp", + LanguageNames.VisualBasic => "VisualBasic", + _ => languageName // handles F#, TypeScript and Xaml + }); } return keyName;