File: ColorSchemes\ColorSchemeApplier.Settings.cs
Web Access
Project: src\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_pxr0p0dn_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// 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.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using NativeMethods = Microsoft.CodeAnalysis.Editor.Wpf.Utilities.NativeMethods;
 
namespace Microsoft.CodeAnalysis.ColorSchemes;
 
internal partial class ColorSchemeApplier
{
    private class ColorSchemeSettings
    {
        private const string ColorSchemeApplierKey = @"Roslyn\ColorSchemeApplier";
        private const string AppliedColorSchemeName = "AppliedColorScheme";
 
        private readonly IThreadingContext _threadingContext;
        private readonly IServiceProvider _serviceProvider;
        private readonly IGlobalOptionService _globalOptions;
 
        public ColorSchemeSettings(
            IThreadingContext threadingContext,
            IServiceProvider serviceProvider,
            IGlobalOptionService globalOptions)
        {
            _threadingContext = threadingContext;
            _serviceProvider = serviceProvider;
            _globalOptions = globalOptions;
        }
 
        public static ImmutableDictionary<ColorSchemeName, ColorScheme> GetColorSchemes()
        {
            return new[]
            {
                ColorSchemeName.VisualStudio2019,
                ColorSchemeName.VisualStudio2017
            }.ToImmutableDictionary(name => name, GetColorScheme);
        }
 
        private static ColorScheme GetColorScheme(ColorSchemeName schemeName)
        {
            using var colorSchemeStream = GetColorSchemeXmlStream(schemeName);
            return ColorSchemeReader.ReadColorScheme(colorSchemeStream);
        }
 
        private static Stream GetColorSchemeXmlStream(ColorSchemeName schemeName)
        {
            var assembly = Assembly.GetExecutingAssembly();
            return assembly.GetManifestResourceStream($"Microsoft.VisualStudio.LanguageServices.ColorSchemes.{schemeName}.xml");
        }
 
        public async Task ApplyColorSchemeAsync(
            ColorSchemeName schemeName, ImmutableArray<RegistryItem> registryItems, CancellationToken cancellationToken)
        {
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
 
            using var registryRoot = VSRegistry.RegistryRoot(_serviceProvider, __VsLocalRegistryType.RegType_Configuration, writable: true);
 
            foreach (var item in registryItems)
            {
                using var itemKey = registryRoot.CreateSubKey(item.SectionName);
                itemKey.SetValue(RegistryItem.ValueName, item.ValueData);
                // Flush RegistryKeys out of paranoia
                itemKey.Flush();
            }
 
            registryRoot.Flush();
 
            SetAppliedColorScheme(schemeName);
 
            // Broadcast that system color settings have changed to force the ColorThemeService to reload colors.
            NativeMethods.PostMessage(NativeMethods.HWND_BROADCAST, NativeMethods.WM_SYSCOLORCHANGE, wparam: IntPtr.Zero, lparam: IntPtr.Zero);
        }
 
        /// <summary>
        /// Get the color scheme that is applied to the configuration registry.
        /// </summary>
        public async Task<ColorSchemeName> GetAppliedColorSchemeAsync(CancellationToken cancellationToken)
        {
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
 
            // The applied color scheme is stored in the configuration registry with the color theme information because
            // when the hive gets rebuilt during upgrades, we need to reapply the color scheme information.
            using var registryRoot = VSRegistry.RegistryRoot(_serviceProvider, __VsLocalRegistryType.RegType_Configuration, writable: false);
            using var itemKey = registryRoot.OpenSubKey(ColorSchemeApplierKey);
            return itemKey is object
                ? (ColorSchemeName)itemKey.GetValue(AppliedColorSchemeName)
                : default;
        }
 
        private void SetAppliedColorScheme(ColorSchemeName schemeName)
        {
            _threadingContext.ThrowIfNotOnUIThread();
 
            // The applied color scheme is stored in the configuration registry with the color theme information because
            // when the hive gets rebuilt during upgrades, we need to reapply the color scheme information.
            using var registryRoot = VSRegistry.RegistryRoot(_serviceProvider, __VsLocalRegistryType.RegType_Configuration, writable: true);
            using var itemKey = registryRoot.CreateSubKey(ColorSchemeApplierKey);
            itemKey.SetValue(AppliedColorSchemeName, (int)schemeName);
            // Flush RegistryKeys out of paranoia
            itemKey.Flush();
        }
 
        public ColorSchemeName GetConfiguredColorScheme()
        {
            var schemeName = _globalOptions.GetOption(ColorSchemeOptionsStorage.ColorScheme);
            return schemeName != ColorSchemeName.None
                ? schemeName
                : ColorSchemeOptionsStorage.ColorScheme.Definition.DefaultValue;
        }
 
        public void MigrateToColorSchemeSetting()
        {
            // Get the preview feature flag value.
            var useEnhancedColorsSetting = _globalOptions.GetOption(ColorSchemeOptionsStorage.LegacyUseEnhancedColors);
 
            // Return if we have already migrated.
            if (useEnhancedColorsSetting == ColorSchemeOptionsStorage.UseEnhancedColors.Migrated)
            {
                return;
            }
 
            var colorScheme = useEnhancedColorsSetting == ColorSchemeOptionsStorage.UseEnhancedColors.DoNotUse
                ? ColorSchemeName.VisualStudio2017
                : ColorSchemeName.VisualStudio2019;
 
            _globalOptions.SetGlobalOption(ColorSchemeOptionsStorage.ColorScheme, colorScheme);
            _globalOptions.SetGlobalOption(ColorSchemeOptionsStorage.LegacyUseEnhancedColors, ColorSchemeOptionsStorage.UseEnhancedColors.Migrated);
        }
    }
}