File: EditorConfigSettings\SettingsEditorControl.xaml.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.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common;
using Microsoft.VisualStudio.Shell.TableControl;
using Microsoft.VisualStudio.TextManager.Interop;
using Roslyn.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings;
 
/// <summary>
/// Interaction logic for SettingsEditorControl.xaml
/// </summary>
internal partial class SettingsEditorControl : UserControl
{
    private readonly ISettingsEditorView[] _views;
    private readonly IWpfTableControl[] _tableControls;
    private readonly Workspace _workspace;
    private readonly string _filepath;
    private readonly IThreadingContext _threadingContext;
    private readonly EditorTextUpdater _textUpdater;
 
    public static string WhitespaceTabTitle => ServicesVSResources.Whitespace;
    public UserControl WhitespaceControl { get; }
    public static string CodeStyleTabTitle => ServicesVSResources.Code_Style;
    public UserControl CodeStyleControl { get; }
    public static string NamingStyleTabTitle => ServicesVSResources.Naming_Style;
    public UserControl NamingStyleControl { get; }
    public static string AnalyzersTabTitle => ServicesVSResources.Analyzers;
    public UserControl AnalyzersControl { get; }
 
    public SettingsEditorControl(ISettingsEditorView whitespaceView,
                                 ISettingsEditorView codeStyleView,
                                 ISettingsEditorView namingStyleView,
                                 ISettingsEditorView analyzerView,
                                 Workspace workspace,
                                 string filepath,
                                 IThreadingContext threadingContext,
                                 IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
                                 IVsTextLines textLines)
    {
        DataContext = this;
        _workspace = workspace;
        _filepath = filepath;
        _threadingContext = threadingContext;
        _textUpdater = new EditorTextUpdater(editorAdaptersFactoryService, textLines);
 
        WhitespaceControl = whitespaceView.SettingControl;
        CodeStyleControl = codeStyleView.SettingControl;
        NamingStyleControl = namingStyleView.SettingControl;
        AnalyzersControl = analyzerView.SettingControl;
 
        _views =
        [
            whitespaceView,
            codeStyleView,
            namingStyleView,
            analyzerView
        ];
 
        _tableControls = [.. _views.SelectAsArray(view => view.TableControl)];
 
        InitializeComponent();
    }
 
    public Border SearchControlParent => SearchControl;
 
    internal void SynchronizeSettings()
    {
        if (!IsKeyboardFocusWithin)
        {
            return;
        }
 
        var solution = _workspace.CurrentSolution;
        var analyzerConfigDocument = solution.Projects
            .Select(p => p.TryGetExistingAnalyzerConfigDocumentAtPath(_filepath))
            .WhereNotNull()
            .FirstOrDefault();
 
        if (analyzerConfigDocument is null)
        {
            return;
        }
 
        _threadingContext.JoinableTaskFactory.Run(async () =>
        {
            var originalText = await analyzerConfigDocument.GetValueTextAsync(default).ConfigureAwait(false);
            var updatedText = originalText;
            foreach (var view in _views)
            {
                // Get any changes for the editors. This will return the source text if there are no changes.
                updatedText = await view.UpdateEditorConfigAsync(updatedText).ConfigureAwait(false);
            }
 
            // Save the updates if they are different from what is currently saved
            if (updatedText != originalText)
            {
                _textUpdater.UpdateText(updatedText.GetTextChanges(originalText));
            }
        });
    }
 
    internal IWpfTableControl[] GetTableControls() => _tableControls;
 
    internal void OnClose()
    {
        foreach (var view in _views)
        {
            view.OnClose();
        }
    }
 
    private void TabsSettingsEditor_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var previousTabItem = e.RemovedItems.Count > 0 ? e.RemovedItems[0] as TabItem : null;
        var selectedTabItem = e.AddedItems.Count > 0 ? e.AddedItems[0] as TabItem : null;
 
        if (previousTabItem is not null && selectedTabItem is not null)
        {
            if (ReferenceEquals(selectedTabItem.Tag, previousTabItem.Tag))
            {
                return;
            }
 
            if (GetTabItem(previousTabItem.Tag) is ContentPresenter prevFrame &&
                GetTabItem(selectedTabItem.Tag) is ContentPresenter currentFrame)
            {
                prevFrame.Visibility = Visibility.Hidden;
                currentFrame.Visibility = Visibility.Visible;
            }
        }
 
        ContentPresenter GetTabItem(object tag)
        {
            if (ReferenceEquals(tag, WhitespaceControl))
            {
                return WhitespaceFrame;
            }
            else if (ReferenceEquals(tag, CodeStyleControl))
            {
                return CodeStyleFrame;
            }
            else if (ReferenceEquals(tag, NamingStyleControl))
            {
                return NamingStyleFrame;
            }
            else if (ReferenceEquals(tag, AnalyzersControl))
            {
                return AnalyzersFrame;
            }
 
            throw ExceptionUtilities.Unreachable();
        }
    }
}