|
// 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.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options;
/// <summary>
/// Stores values of options read from global options and values set to these options.
/// Not thread safe.
/// </summary>
internal sealed class OptionStore : IOptionsReader
{
public readonly IGlobalOptionService GlobalOptions;
public event EventHandler<OptionKey2>? OptionChanged;
/// <summary>
/// Cached values read from global options.
/// </summary>
private ImmutableDictionary<OptionKey2, object?> _globalValues;
/// <summary>
/// Updated values.
/// </summary>
private ImmutableDictionary<OptionKey2, object?> _updatedValues;
public OptionStore(IGlobalOptionService globalOptions)
{
GlobalOptions = globalOptions;
_globalValues = ImmutableDictionary<OptionKey2, object?>.Empty;
_updatedValues = ImmutableDictionary<OptionKey2, object?>.Empty;
}
public void Clear()
{
_globalValues = ImmutableDictionary<OptionKey2, object?>.Empty;
_updatedValues = ImmutableDictionary<OptionKey2, object?>.Empty;
}
public ImmutableArray<(OptionKey2 key, object? oldValue, object? newValue)> GetChangedOptions()
=> _updatedValues.SelectAsArray(entry => (entry.Key, _globalValues[entry.Key], entry.Value));
bool IOptionsReader.TryGetOption<T>(OptionKey2 optionKey, out T value)
{
value = (T)GetOption(optionKey)!;
return true;
}
public T GetOption<T>(Option2<T> option)
=> (T)GetOption(new OptionKey2(option))!;
public T GetOption<T>(PerLanguageOption2<T> option, string language)
=> (T)GetOption(new OptionKey2(option, language))!;
public T GetOption<T>(IOption2 option, string? language)
{
Debug.Assert(option.IsPerLanguage == language is not null);
return (T)GetOption(new OptionKey2(option, language))!;
}
private object? GetOption(OptionKey2 optionKey)
{
if (_updatedValues.TryGetValue(optionKey, out var value))
{
return value;
}
if (_globalValues.TryGetValue(optionKey, out value))
{
return value;
}
value = GlobalOptions.GetOption<object?>(optionKey);
_globalValues = _globalValues.Add(optionKey, value);
return value;
}
public void SetOption<T>(Option2<T> option, T value)
=> SetOption(new OptionKey2(option), value);
public void SetOption<T>(PerLanguageOption2<T> option, string language, T value)
=> SetOption(new OptionKey2(option, language), value);
public void SetOption(IOption2 option, string? language, object? value)
{
Debug.Assert(option.IsPerLanguage == language is not null);
SetOption(new OptionKey2(option, language), value);
}
private void SetOption(OptionKey2 optionKey, object? value)
{
var currentValue = GetOption(optionKey);
if (!Equals(value, currentValue))
{
_updatedValues = _updatedValues.SetItem(optionKey, value);
OptionChanged?.Invoke(this, optionKey);
}
}
}
|