diff --git a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb index 55f3a531d47801715f6a4378cc7ec94e7e5ea06c..52b94238e9db1f8aea397be28a813c9ffd6f1c29 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticServiceTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Shared.Options Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.UnitTests.Diagnostics @@ -1915,6 +1916,9 @@ class MyClass Using workspace = TestWorkspace.CreateWorkspace(test) + ' set csharp closed diagnostic option on + workspace.Options = workspace.Options.WithChangedOption(ServiceFeatureOnOffOptions.ClosedFileDiagnostic, LanguageNames.CSharp, True) + Dim project = workspace.CurrentSolution.Projects.Single() ' Add analyzer diff --git a/src/Features/Core/Portable/Shared/Options/ServiceFeatureOnOffOptions.cs b/src/Features/Core/Portable/Shared/Options/ServiceFeatureOnOffOptions.cs index 4d747c45e9928dbdda35e12187c238756a81827e..2611ec985411679274fc969cbe59c63d178f0054 100644 --- a/src/Features/Core/Portable/Shared/Options/ServiceFeatureOnOffOptions.cs +++ b/src/Features/Core/Portable/Shared/Options/ServiceFeatureOnOffOptions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Shared.Options @@ -13,6 +14,7 @@ internal static class ServiceFeatureOnOffOptions /// this option doesn't mean we will show all diagnostics that belong to opened files when turned off, /// rather it means we will only show diagnostics that are cheap to calculate for small scope such as opened files. /// - public static readonly PerLanguageOption ClosedFileDiagnostic = new PerLanguageOption(OptionName, "Closed File Diagnostic", defaultValue: true); + public static readonly PerLanguageOption ClosedFileDiagnostic = new PerLanguageOption( + OptionName, "Closed File Diagnostic", defaultValue: true, perLanguageDefaults: ImmutableDictionary.Empty.Add(LanguageNames.CSharp, false)); } } diff --git a/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs b/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs index bcd282f6fe838993a08b3db1b944d224c0ad6b44..dc87ba018ab1cb08fb284f5674a6c54e28176a09 100644 --- a/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs +++ b/src/VisualStudio/Core/Impl/Options/AbstractSettingStoreOptionSerializer.cs @@ -34,7 +34,7 @@ public virtual bool TryPersist(OptionKey optionKey, object value) return TryPersist(optionKey, value, (r, k, o, v) => r.SetValue(k, (bool)v ? 1 : 0, RegistryValueKind.DWord)); } - protected bool TryFetch(OptionKey optionKey, Func valueGetter, out object value) + protected bool TryFetch(OptionKey optionKey, Func valueGetter, out object value) { if (this.RegistryKey == null) { @@ -58,7 +58,7 @@ protected bool TryFetch(OptionKey optionKey, Func public IOption Option { get; } public string Language { get; } + internal object DefaultValue => ((IOption2)Option).GetDefaultValue(Language); + public OptionKey(IOption option, string language = null) { if (option == null) diff --git a/src/Workspaces/Core/Portable/Options/OptionService.cs b/src/Workspaces/Core/Portable/Options/OptionService.cs index de73f3c956e4eb536fea71fa10a7f035017e27b6..c6a30107eff9d131de505d2a36d9fb2ca0d8817e 100644 --- a/src/Workspaces/Core/Portable/Options/OptionService.cs +++ b/src/Workspaces/Core/Portable/Options/OptionService.cs @@ -81,7 +81,7 @@ private object LoadOptionFromSerializerOrGetDefault(OptionKey optionKey) // Just use the default. We will still cache this so we aren't trying to deserialize // over and over. - return optionKey.Option.DefaultValue; + return optionKey.DefaultValue; } } diff --git a/src/Workspaces/Core/Portable/Options/OptionSet.cs b/src/Workspaces/Core/Portable/Options/OptionSet.cs index eac193bb2ec29be8dcef1b7dc6fe855628b5c90f..2c9acd7f0f939061ccef1cb6a7fca9c5d1e5d279 100644 --- a/src/Workspaces/Core/Portable/Options/OptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/OptionSet.cs @@ -51,7 +51,7 @@ public object GetOption(OptionKey optionKey) if (!_values.TryGetValue(optionKey, out value)) { - value = _service != null ? _service.GetOption(optionKey) : optionKey.Option.DefaultValue; + value = _service != null ? _service.GetOption(optionKey) : optionKey.DefaultValue; _values = _values.Add(optionKey, value); } diff --git a/src/Workspaces/Core/Portable/Options/Option`1.cs b/src/Workspaces/Core/Portable/Options/Option`1.cs index 5c8bea66b814e9cd5c1ff65170cc6dc3f96e2e6f..521c7414f3fa01ad702a85d5e2f4979f89390295 100644 --- a/src/Workspaces/Core/Portable/Options/Option`1.cs +++ b/src/Workspaces/Core/Portable/Options/Option`1.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Options /// /// An global option. An instance of this class can be used to access an option value from an OptionSet. /// - public class Option : IOption + public class Option : IOption2, IOption { /// /// Feature this option is associated with. @@ -22,10 +22,7 @@ public class Option : IOption /// /// The type of the option value. /// - public Type Type - { - get { return typeof(T); } - } + public Type Type => typeof(T); /// /// The default value of the option. @@ -49,19 +46,13 @@ public Option(string feature, string name, T defaultValue = default(T)) this.DefaultValue = defaultValue; } - Type IOption.Type - { - get { return typeof(T); } - } - - object IOption.DefaultValue - { - get { return this.DefaultValue; } - } + Type IOption.Type => typeof(T); + object IOption.DefaultValue => this.DefaultValue; + bool IOption.IsPerLanguage => false; - bool IOption.IsPerLanguage + object IOption2.GetDefaultValue(string language) { - get { return false; } + return this.DefaultValue; } public override string ToString() diff --git a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs index 23398e14ad9820611e827aab1571fd9e26d1e0e9..ae04592fb490fe3b2c18eb0ab82955f426a83f5a 100644 --- a/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs +++ b/src/Workspaces/Core/Portable/Options/PerLanguageOption.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; +using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Options { @@ -8,8 +10,13 @@ namespace Microsoft.CodeAnalysis.Options /// An option that can be specified once per language. /// /// - public class PerLanguageOption : IOption + public class PerLanguageOption : IOption2, IOption { + /// + /// Save per language defaults + /// + private readonly IImmutableDictionary _perLanguageDefaults; + /// /// Feature this option is associated with. /// @@ -33,7 +40,32 @@ public Type Type /// public T DefaultValue { get; } - public PerLanguageOption(string feature, string name, T defaultValue) + /// + /// The default option value of specific language + /// + internal T GetDefaultValue(string language) + { + if (_perLanguageDefaults.Count == 0) + { + return DefaultValue; + } + + T languageSpecificDefault; + if (!_perLanguageDefaults.TryGetValue(language, out languageSpecificDefault)) + { + return DefaultValue; + } + + return languageSpecificDefault; + } + + public PerLanguageOption(string feature, string name, T defaultValue) : + this(feature, name, defaultValue, ImmutableDictionary.Empty) + { + } + + internal PerLanguageOption( + string feature, string name, T defaultValue, IDictionary perLanguageDefaults) { if (string.IsNullOrWhiteSpace(feature)) { @@ -45,9 +77,18 @@ public PerLanguageOption(string feature, string name, T defaultValue) throw new ArgumentException(nameof(name)); } + if (perLanguageDefaults == null) + { + throw new ArgumentNullException(nameof(perLanguageDefaults)); + } + this.Feature = feature; this.Name = name; this.DefaultValue = defaultValue; + + this._perLanguageDefaults = + (perLanguageDefaults as IImmutableDictionary) ?? + ImmutableDictionary.CreateRange(perLanguageDefaults); } Type IOption.Type @@ -65,6 +106,11 @@ bool IOption.IsPerLanguage get { return true; } } + object IOption2.GetDefaultValue(string language) + { + return this.GetDefaultValue(language); + } + public override string ToString() { return string.Format("{0} - {1}", this.Feature, this.Name); diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index 6e59591f1bb84d705cde514902e23ab1518abe14..2dcb9fbdcee9244d5754050217d0a2fe3d2e45c7 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -387,6 +387,7 @@ +