Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
using Microsoft.CodeAnalysis.Razor.Workspaces.Settings;
using Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.AspNetCore.Razor.LanguageServer;

[Export(typeof(IRazorCohostStartupService))]
[method: ImportingConstructor]
internal sealed class SemanticTokensRefreshNotifier(IClientSettingsManager clientSettingsManager) : IRazorCohostStartupService, IDisposable
{
private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager;

private IRazorClientLanguageServerManager? _razorClientLanguageServerManager;
private bool _lastColorBackground;

public int Order => WellKnownStartupOrder.Default;

public Task StartupAsync(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
{
_razorClientLanguageServerManager = requestContext.GetRequiredService<IRazorClientLanguageServerManager>();

if (clientCapabilities.Workspace?.SemanticTokens?.RefreshSupport ?? false)
{
_lastColorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground;
_clientSettingsManager.ClientSettingsChanged += ClientSettingsManager_ClientSettingsChanged;
}

return Task.CompletedTask;
}

private void ClientSettingsManager_ClientSettingsChanged(object sender, EventArgs e)
{
var colorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground;
if (colorBackground == _lastColorBackground)
{
return;
}

_lastColorBackground = colorBackground;
_razorClientLanguageServerManager.AssumeNotNull().SendNotificationAsync(Methods.WorkspaceSemanticTokensRefreshName, CancellationToken.None).Forget();
}

public void Dispose()
{
_clientSettingsManager.ClientSettingsChanged -= ClientSettingsManager_ClientSettingsChanged;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Settings;
using Microsoft.CodeAnalysis.Razor.Telemetry;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Razor.Settings;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Settings;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities.UnifiedSettings;

Expand All @@ -26,91 +23,24 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Options;
[Export(typeof(IAdvancedSettingsStorage))]
internal class OptionsStorage : IAdvancedSettingsStorage, IDisposable
{
private readonly WritableSettingsStore _writableSettingsStore;
private readonly Lazy<ITelemetryReporter> _telemetryReporter;
private readonly JoinableTask _initializeTask;
private ImmutableArray<string> _taskListDescriptors = [];
private ISettingsReader? _unifiedSettingsReader;
private IDisposable? _unifiedSettingsSubscription;
private bool _changedBeforeSubscription;

public bool FormatOnType
{
get => GetBool(SettingsNames.FormatOnType.LegacyName, defaultValue: true);
set => SetBool(SettingsNames.FormatOnType.LegacyName, value);
}

public bool AutoClosingTags
{
get => GetBool(SettingsNames.AutoClosingTags.LegacyName, defaultValue: true);
set => SetBool(SettingsNames.AutoClosingTags.LegacyName, value);
}

public bool AutoInsertAttributeQuotes
{
get => GetBool(SettingsNames.AutoInsertAttributeQuotes.LegacyName, defaultValue: true);
set => SetBool(SettingsNames.AutoInsertAttributeQuotes.LegacyName, value);
}

public bool ColorBackground
{
get => GetBool(SettingsNames.ColorBackground.LegacyName, defaultValue: false);
set => SetBool(SettingsNames.ColorBackground.LegacyName, value);
}

public bool CodeBlockBraceOnNextLine
{
get => GetBool(SettingsNames.CodeBlockBraceOnNextLine.LegacyName, defaultValue: false);
set => SetBool(SettingsNames.CodeBlockBraceOnNextLine.LegacyName, value);
}

public bool CommitElementsWithSpace
{
get => GetBool(SettingsNames.CommitElementsWithSpace.LegacyName, defaultValue: true);
set => SetBool(SettingsNames.CommitElementsWithSpace.LegacyName, value);
}

public SnippetSetting Snippets
{
get => (SnippetSetting)GetInt(SettingsNames.Snippets.LegacyName, (int)SnippetSetting.All);
set => SetInt(SettingsNames.Snippets.LegacyName, (int)value);
}

public LogLevel LogLevel
{
get => (LogLevel)GetInt(SettingsNames.LogLevel.LegacyName, (int)LogLevel.Warning);
set => SetInt(SettingsNames.LogLevel.LegacyName, (int)value);
}

public bool FormatOnPaste
{
get => GetBool(SettingsNames.FormatOnPaste.LegacyName, defaultValue: true);
set => SetBool(SettingsNames.FormatOnPaste.LegacyName, value);
}

public ImmutableArray<string> TaskListDescriptors
{
get { return _taskListDescriptors; }
}

[ImportingConstructor]
public OptionsStorage(
SVsServiceProvider synchronousServiceProvider,
[Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider,
Lazy<ITelemetryReporter> telemetryReporter,
JoinableTaskContext joinableTaskContext)
{
var shellSettingsManager = new ShellSettingsManager(synchronousServiceProvider);
_writableSettingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);

_writableSettingsStore.CreateCollection(SettingsNames.LegacyCollection);
_telemetryReporter = telemetryReporter;

_initializeTask = joinableTaskContext.Factory.RunAsync(async () =>
{
var unifiedSettingsManager = await serviceProvider.GetServiceAsync<SVsUnifiedSettingsManager, Utilities.UnifiedSettings.ISettingsManager>();
var unifiedSettingsManager = await serviceProvider.GetServiceAsync<SVsUnifiedSettingsManager, ISettingsManager>();
_unifiedSettingsReader = unifiedSettingsManager.GetReader();
_unifiedSettingsSubscription = _unifiedSettingsReader.SubscribeToChanges(OnUnifiedSettingsChanged, SettingsNames.AllSettings.Select(s => s.UnifiedName).ToArray());
_unifiedSettingsSubscription = _unifiedSettingsReader.SubscribeToChanges(OnUnifiedSettingsChanged, SettingsNames.AllSettings);

await GetTaskListDescriptorsAsync(joinableTaskContext.Factory, serviceProvider);
});
Expand Down Expand Up @@ -168,44 +98,41 @@ public async Task OnChangedAsync(Action<ClientAdvancedSettings> changed)
private EventHandler<ClientAdvancedSettingsChangedEventArgs>? _changed;

public ClientAdvancedSettings GetAdvancedSettings()
=> new(FormatOnType, AutoClosingTags, AutoInsertAttributeQuotes, ColorBackground, CodeBlockBraceOnNextLine, CommitElementsWithSpace, Snippets, LogLevel, FormatOnPaste, TaskListDescriptors);
=> new(
GetBool(SettingsNames.FormatOnType, defaultValue: true),
GetBool(SettingsNames.AutoClosingTags, defaultValue: true),
GetBool(SettingsNames.AutoInsertAttributeQuotes, defaultValue: true),
GetBool(SettingsNames.ColorBackground, defaultValue: false),
GetBool(SettingsNames.CodeBlockBraceOnNextLine, defaultValue: false),
GetBool(SettingsNames.CommitElementsWithSpace, defaultValue: true),
GetEnum(SettingsNames.Snippets, SnippetSetting.All),
GetEnum(SettingsNames.LogLevel, LogLevel.Warning),
GetBool(SettingsNames.FormatOnPaste, defaultValue: true),
_taskListDescriptors);

public bool GetBool(string name, bool defaultValue)
{
if (_writableSettingsStore.PropertyExists(SettingsNames.LegacyCollection, name))
if (_unifiedSettingsReader.AssumeNotNull().GetValue<bool>(name) is { Outcome: SettingRetrievalOutcome.Success, Value: { } unifiedValue })
{
return _writableSettingsStore.GetBoolean(SettingsNames.LegacyCollection, name);
return unifiedValue;
}

return defaultValue;
}

public void SetBool(string name, bool value)
public T GetEnum<T>(string name, T defaultValue) where T : struct, Enum
{
_writableSettingsStore.SetBoolean(SettingsNames.LegacyCollection, name, value);
_telemetryReporter.Value.ReportEvent("OptionChanged", Severity.Normal, new Property(name, value));

NotifyChange();
}

public int GetInt(string name, int defaultValue)
{
if (_writableSettingsStore.PropertyExists(SettingsNames.LegacyCollection, name))
if (_unifiedSettingsReader.AssumeNotNull().GetValue<string>(name) is { Outcome: SettingRetrievalOutcome.Success, Value: { } unifiedValue })
{
return _writableSettingsStore.GetInt32(SettingsNames.LegacyCollection, name);
if (Enum.TryParse<T>(unifiedValue, ignoreCase: true, out var parsed))
{
return parsed;
}
}

return defaultValue;
}

public void SetInt(string name, int value)
{
_writableSettingsStore.SetInt32(SettingsNames.LegacyCollection, name, value);
_telemetryReporter.Value.ReportEvent("OptionChanged", Severity.Normal, new Property(name, value));

NotifyChange();
}

private void NotifyChange()
{
_initializeTask.Join();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ namespace Microsoft.VisualStudio.Razor.LanguageClient.Options;

internal static class SettingsNames
{
public record Setting(string LegacyName, string UnifiedName);
public const string UnifiedCollection = "languages.razor.advanced";

public const string LegacyCollection = "Razor";
public const string UnifiedCollection = "textEditor.razor.advanced";
public static readonly string FormatOnType = UnifiedCollection + ".formatOnType";
public static readonly string AutoClosingTags = UnifiedCollection + ".autoClosingTags";
public static readonly string AutoInsertAttributeQuotes = UnifiedCollection + ".autoInsertAttributeQuotes";
public static readonly string ColorBackground = UnifiedCollection + ".colorBackground";
public static readonly string CodeBlockBraceOnNextLine = UnifiedCollection + ".codeBlockBraceOnNextLine";
public static readonly string CommitElementsWithSpace = UnifiedCollection + ".commitCharactersWithSpace";
public static readonly string Snippets = UnifiedCollection + ".snippets";
public static readonly string LogLevel = UnifiedCollection + ".logLevel";
public static readonly string FormatOnPaste = UnifiedCollection + ".formatOnPaste";

public static readonly Setting FormatOnType = new("FormatOnType", UnifiedCollection + ".formatOnType");
public static readonly Setting AutoClosingTags = new("AutoClosingTags", UnifiedCollection + ".autoClosingTags");
public static readonly Setting AutoInsertAttributeQuotes = new("AutoInsertAttributeQuotes", UnifiedCollection + ".autoInsertAttributeQuotes");
public static readonly Setting ColorBackground = new("ColorBackground", UnifiedCollection + ".colorBackground");
public static readonly Setting CodeBlockBraceOnNextLine = new("CodeBlockBraceOnNextLine", UnifiedCollection + ".codeBlockBraceOnNextLine");
public static readonly Setting CommitElementsWithSpace = new("CommitElementsWithSpace", UnifiedCollection + ".commitCharactersWithSpace");
public static readonly Setting Snippets = new("Snippets", UnifiedCollection + ".snippets");
public static readonly Setting LogLevel = new("LogLevel", UnifiedCollection + ".logLevel");
public static readonly Setting FormatOnPaste = new("FormatOnPaste", UnifiedCollection + ".formatOnPaste");

public static readonly Setting[] AllSettings =
public static readonly string[] AllSettings =
[
FormatOnType,
AutoClosingTags,
Expand Down