/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/modules/cmdpal/Microsoft.CmdPal.UI/ViewModels/DevRibbonViewModel.cs
204 строки
7 KB
Jiří Polášek
CmdPal: Add a button to toggle the visibility of the dev ribbon (#45379)
10 фев 2026, 03:15
Не верифицирован
10 фев 2026, 03:15
521d34f
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Text.RegularExpressions; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using ManagedCommon; using Microsoft.CmdPal.UI.Helpers; using Microsoft.CmdPal.UI.Messages; using Microsoft.UI; using Windows.System; using Windows.UI; using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue; namespace Microsoft.CmdPal.UI.ViewModels; internal sealed partial class DevRibbonViewModel : ObservableObject { private const int MaxLogEntries = 2; private const string Release = "Release"; private const string Debug = "Debug"; private static readonly Color ReleaseAotColor = ColorHelper.FromArgb(255, 124, 58, 237); private static readonly Color ReleaseColor = ColorHelper.FromArgb(255, 51, 65, 85); private static readonly Color DebugAotColor = ColorHelper.FromArgb(255, 99, 102, 241); private static readonly Color DebugColor = ColorHelper.FromArgb(255, 107, 114, 128); private readonly DispatcherQueue _dispatcherQueue; public DevRibbonViewModel() { _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); Trace.Listeners.Add(new DevRibbonTraceListener(this)); var configLabel = BuildConfiguration == Release ? "RLS" : "DBG"; /* #no-spell-check-line */ var aotLabel = BuildInfo.IsNativeAot ? "⚡AOT" : "NO AOT"; Tag = $"{configLabel} | {aotLabel}"; TagColor = (BuildConfiguration, BuildInfo.IsNativeAot) switch { (Release, true) => ReleaseAotColor, (Release, false) => ReleaseColor, (Debug, true) => DebugAotColor, (Debug, false) => DebugColor, _ => Colors.Fuchsia, }; } public string BuildConfiguration => BuildInfo.Configuration; public bool IsAotReleaseConfiguration => BuildConfiguration == Release && BuildInfo.IsNativeAot; public bool IsAot => BuildInfo.IsNativeAot; public bool IsPublishTrimmed => BuildInfo.PublishTrimmed; public ObservableCollection<LogEntryViewModel> LatestLogs { get; } = []; [ObservableProperty] public partial int WarningCount { get; private set; } [ObservableProperty] public partial int ErrorCount { get; private set; } [ObservableProperty] public partial string Tag { get; private set; } [ObservableProperty] public partial Color TagColor { get; private set; } [RelayCommand] private async Task OpenLogFileAsync() { var logPath = Logger.CurrentLogFile; if (File.Exists(logPath)) { await Launcher.LaunchUriAsync(new Uri(logPath)); } } [RelayCommand] private async Task OpenLogFolderAsync() { var logFolderPath = Logger.CurrentVersionLogDirectoryPath; if (Directory.Exists(logFolderPath)) { await Launcher.LaunchFolderPathAsync(logFolderPath); } } [RelayCommand] private void ResetErrorCounters() { WarningCount = 0; ErrorCount = 0; LatestLogs.Clear(); } [RelayCommand] private void OpenInternalTools() { WeakReferenceMessenger.Default.Send(new OpenSettingsMessage("Internal")); } [RelayCommand] private void ToggleDevRibbonVisibility() { WeakReferenceMessenger.Default.Send(new ToggleDevRibbonMessage()); } private sealed partial class DevRibbonTraceListener(DevRibbonViewModel viewModel) : TraceListener { private const string TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff"; [GeneratedRegex(@"^\[(?<timestamp>.*?)\] \[(?<severity>.*?)\] (?<message>.*)")] private static partial Regex LogRegex(); private readonly Lock _lock = new(); private LogEntryViewModel? _latestLogEntry; public override void Write(string? message) { // Not required for this scenario. } public override void WriteLine(string? message) { if (message is null) { return; } lock (_lock) { var match = LogRegex().Match(message); if (match.Success) { var severity = match.Groups["severity"].Value; var isWarning = severity.Equals("Warning", StringComparison.OrdinalIgnoreCase); var isError = severity.Equals("Error", StringComparison.OrdinalIgnoreCase); if (isWarning || isError) { var timestampStr = match.Groups["timestamp"].Value; var timestamp = DateTimeOffset.TryParseExact( timestampStr, TimestampFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var parsed) ? parsed : DateTimeOffset.Now; var logEntry = new LogEntryViewModel( timestamp, severity, match.Groups["message"].Value, string.Empty); _latestLogEntry = logEntry; viewModel._dispatcherQueue.TryEnqueue(() => { if (isWarning) { viewModel.WarningCount++; } else { viewModel.ErrorCount++; } viewModel.LatestLogs.Insert(0, logEntry); while (viewModel.LatestLogs.Count > MaxLogEntries) { viewModel.LatestLogs.RemoveAt(viewModel.LatestLogs.Count - 1); } }); } else { _latestLogEntry = null; } return; } if (IndentLevel > 0 && _latestLogEntry is { } latest) { viewModel._dispatcherQueue.TryEnqueue(() => { latest.AppendDetails(message); }); } } } } }