From 9b9eb284cb9e701a4a5d115fb1ec4c333e8739fc Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 17 Jul 2024 11:08:32 -0400 Subject: [PATCH 01/25] Move GridValue copy button inside a menu --- .../Components/Controls/GridValue.razor | 22 ++++++++++++++++++- .../Components/Controls/GridValue.razor.cs | 13 ++++++----- src/Aspire.Dashboard/wwwroot/js/app.js | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index bf60cd5cc5c..490de8c5411 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -42,7 +42,7 @@ ]; } - @PreCopyToolTip +--> + + + + + + + + + + @PreCopyToolTip + + diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs index 5237ed1ca2a..fe83790a63b 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs @@ -7,7 +7,7 @@ namespace Aspire.Dashboard.Components.Controls; -public partial class GridValue : IDisposable +public partial class GridValue { [Parameter, EditorRequired] public string? Value { get; set; } @@ -60,9 +60,9 @@ public partial class GridValue : IDisposable private readonly Icon _maskIcon = new Icons.Regular.Size16.EyeOff(); private readonly Icon _unmaskIcon = new Icons.Regular.Size16.Eye(); - private readonly string _anchorId = $"copy-{Guid.NewGuid():N}"; - - private FluentTooltip? _tooltipComponent; + private readonly string _copyAnchorId = $"copy-{Guid.NewGuid():N}"; + private readonly string _menuAnchorId = $"menu-{Guid.NewGuid():N}"; + private bool _isMenuOpen; protected override void OnInitialized() { @@ -85,8 +85,9 @@ private string TrimLength(string? text) return text ?? ""; } - public void Dispose() + private void ToggleMenuOpen() { - _tooltipComponent?.Dispose(); + _isMenuOpen = !_isMenuOpen; } + } diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index 9ef506ebb50..f86f04d492d 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -17,7 +17,7 @@ if (firstUndefinedElement) { // Register a global click event listener to handle copy button clicks. // Required because an "onclick" attribute is denied by CSP. document.addEventListener("click", function (e) { - if (e.target.type === "button" && e.target.getAttribute("data-copybutton")) { + if (e.target.tagName.toLowerCase() === "fluent-menu-item" && e.target.getAttribute("data-copybutton")) { buttonCopyTextToClipboard(e.target); e.stopPropagation(); } From 1aeb0de0a1d4236defcbef0d59cff94bf9f24218 Mon Sep 17 00:00:00 2001 From: Adam Ratzman Date: Wed, 17 Jul 2024 11:55:22 -0400 Subject: [PATCH 02/25] add empty dialog --- .../Components/Controls/GridValue.razor | 32 ++++++++++----- .../Components/Controls/GridValue.razor.cs | 40 ++++++++++++++++++- .../Components/Controls/PropertyGrid.razor | 13 ++++-- .../Components/Controls/ResourceDetails.razor | 17 ++++++-- .../Dialogs/TextVisualizerDialog.razor | 9 +++++ .../Dialogs/TextVisualizerDialog.razor.cs | 11 +++++ .../LogMessageColumnDisplay.razor | 2 + .../SourceColumnDisplay.razor | 5 ++- .../Model/TextVisualizerDialogViewModel.cs | 6 +++ 9 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor create mode 100644 src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs create mode 100644 src/Aspire.Dashboard/Model/TextVisualizerDialogViewModel.cs diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index 490de8c5411..d749488c187 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -60,15 +60,25 @@ - - - - - - @PreCopyToolTip - - +
+ + + + + + @PreCopyToolTip + + + + + + + + Open in text visualizer + + +
diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs index fe83790a63b..bbd997145a6 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Aspire.Dashboard.Components.Dialogs; +using Aspire.Dashboard.Components.Resize; +using Aspire.Dashboard.Model; using Aspire.Dashboard.Resources; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; @@ -12,6 +15,9 @@ public partial class GridValue [Parameter, EditorRequired] public string? Value { get; set; } + [Parameter, EditorRequired] + public required string ValueDescription { get; set; } + /// /// Content to include, if any, after the Value string /// @@ -54,9 +60,17 @@ public partial class GridValue [Parameter] public string? ToolTip { get; set; } - [Parameter] public string PreCopyToolTip { get; set; } = null!; + [Parameter] + public string PreCopyToolTip { get; set; } = null!; + + [Parameter] + public string PostCopyToolTip { get; set; } = null!; + + [Inject] + public required IDialogService DialogService { get; init; } - [Parameter] public string PostCopyToolTip { get; set; } = null!; + [CascadingParameter] + public required ViewportInformation ViewportInformation { get; init; } private readonly Icon _maskIcon = new Icons.Regular.Size16.EyeOff(); private readonly Icon _unmaskIcon = new Icons.Regular.Size16.Eye(); @@ -90,4 +104,26 @@ private void ToggleMenuOpen() _isMenuOpen = !_isMenuOpen; } + private async Task OpenTextVisualizerAsync() + { + var parameters = new DialogParameters + { + Title = ValueDescription, + PrimaryActionEnabled = false, + SecondaryActionEnabled = false, + Width = ViewportInformation.IsDesktop ? "60vw" : "100vw", + Height = ViewportInformation.IsDesktop ? "60vh" : "100vh", + TrapFocus = true, + Modal = true, + PreventScroll = true + }; + + await DialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(Value!), parameters); + } + +#pragma warning disable CA1822 + private void Test(MenuChangeEventArgs args) +#pragma warning restore CA1822 + { + } } diff --git a/src/Aspire.Dashboard/Components/Controls/PropertyGrid.razor b/src/Aspire.Dashboard/Components/Controls/PropertyGrid.razor index 06695bd5de7..875a0e9aec5 100644 --- a/src/Aspire.Dashboard/Components/Controls/PropertyGrid.razor +++ b/src/Aspire.Dashboard/Components/Controls/PropertyGrid.razor @@ -8,12 +8,17 @@ GenerateHeader="GenerateHeaderOption.Sticky" GridTemplateColumns="@GridTemplateColumns"> - + - + @ExtraValueContent(context) diff --git a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor index fe1982275b7..1c056d83959 100644 --- a/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor +++ b/src/Aspire.Dashboard/Components/Controls/ResourceDetails.razor @@ -49,10 +49,16 @@ GenerateHeader="GenerateHeaderOption.Sticky" GridTemplateColumns="1fr 1.5fr"> - + - + @@ -68,10 +74,13 @@ GenerateHeader="GenerateHeaderOption.Sticky" GridTemplateColumns="1fr 1.5fr"> - + - + @if (context.Url != null) { diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor new file mode 100644 index 00000000000..90054f34ae2 --- /dev/null +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -0,0 +1,9 @@ +@using Aspire.Dashboard.Model +@implements IDialogContentComponent + +@Content.Text + +@code { + [Parameter, EditorRequired] + public required TextVisualizerDialogViewModel Content { get; set; } +} diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs new file mode 100644 index 00000000000..aaf3e133275 --- /dev/null +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Components; + +namespace Aspire.Dashboard.Components.Dialogs; + +public partial class TextVisualizerDialog : ComponentBase +{ +} + diff --git a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor index f40fdbb85a0..96bb15a0c4d 100644 --- a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor +++ b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor @@ -7,6 +7,7 @@ @inject IJSRuntime JS @inject IStringLocalizer ControlsStringsLoc @inject IStringLocalizer Loc +@inject IStringLocalizer StructuredLogsLoc @if (_hasErrorInfo) @@ -48,6 +49,7 @@ } diff --git a/src/Aspire.Dashboard/Components/ResourcesGridColumns/SourceColumnDisplay.razor b/src/Aspire.Dashboard/Components/ResourcesGridColumns/SourceColumnDisplay.razor index 8190be08052..62e674e9a19 100644 --- a/src/Aspire.Dashboard/Components/ResourcesGridColumns/SourceColumnDisplay.razor +++ b/src/Aspire.Dashboard/Components/ResourcesGridColumns/SourceColumnDisplay.razor @@ -1,12 +1,14 @@ @using Aspire.Dashboard.Model -@using Aspire.Dashboard.Extensions @using Aspire.Dashboard.Resources + @inject IStringLocalizer Loc +@inject IStringLocalizer ResourcesLoc @if (ContentAfterValue is not null) { Date: Mon, 22 Jul 2024 13:24:52 -0400 Subject: [PATCH 03/25] test --- .../Components/Controls/GridValue.razor | 50 +++++++------------ .../Components/Controls/GridValue.razor.cs | 46 +++++++++++++---- src/Aspire.Dashboard/wwwroot/js/app.js | 16 ++++++ 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index d749488c187..9c2b1a43ec6 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -34,7 +34,7 @@ } @{ - (string, object)[] uncapturedAttributes = [ + (string, object)[] uncapturedCopyAttributes = [ ("alt", PreCopyToolTip), ("title", string.Empty), ("aria-label", Loc[nameof(ControlsStrings.GridValueCopyToClipboard)]), @@ -42,16 +42,6 @@ ]; } - + -
- - - - - - @PreCopyToolTip - + + + + + + @PreCopyToolTip + - - - - + + + + - Open in text visualizer - - -
- + Open in text visualizer + + diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs index bbd997145a6..887729b9174 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs @@ -5,8 +5,10 @@ using Aspire.Dashboard.Components.Resize; using Aspire.Dashboard.Model; using Aspire.Dashboard.Resources; +using Aspire.Dashboard.Utils; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; +using Microsoft.JSInterop; namespace Aspire.Dashboard.Components.Controls; @@ -69,14 +71,20 @@ public partial class GridValue [Inject] public required IDialogService DialogService { get; init; } + [Inject] + public required IJSRuntime JS { get; init; } + [CascadingParameter] public required ViewportInformation ViewportInformation { get; init; } private readonly Icon _maskIcon = new Icons.Regular.Size16.EyeOff(); private readonly Icon _unmaskIcon = new Icons.Regular.Size16.Eye(); - private readonly string _copyAnchorId = $"copy-{Guid.NewGuid():N}"; + private readonly string _copyId = $"copy-{Guid.NewGuid():N}"; private readonly string _menuAnchorId = $"menu-{Guid.NewGuid():N}"; + private readonly string _openVisualizerId = $"open-visualizer-{Guid.NewGuid():N}"; private bool _isMenuOpen; + private IJSObjectReference? _onClickHandler; + private DotNetObjectReference? _thisReference; protected override void OnInitialized() { @@ -84,7 +92,32 @@ protected override void OnInitialized() PostCopyToolTip = Loc[nameof(ControlsStrings.GridValueCopied)]; } - private string GetContainerClass() => EnableMasking ? "container masking-enabled wrap" : "container wrap"; + private async Task OnOpenChangedAsync() + { + if (_isMenuOpen) + { + _thisReference?.Dispose(); + + try + { + await JS.InvokeVoidAsync("window.unregisterGlobalKeydownListener", _openVisualizerId, _onClickHandler); + } + catch (JSDisconnectedException) + { + // Per https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0#javascript-interop-calls-without-a-circuit + // this is one of the calls that will fail if the circuit is disconnected, and we just need to catch the exception so it doesn't pollute the logs + } + + await JSInteropHelpers.SafeDisposeAsync(_onClickHandler); + } + else + { + _thisReference = DotNetObjectReference.Create(this); + _onClickHandler = await JS.InvokeAsync("window.registerOpenTextVisualizerOnClick", _openVisualizerId, _thisReference); + } + } + + private string GetContainerClass() => EnableMasking ? "container masking-enabled" : "container"; private async Task ToggleMaskStateAsync() => await IsMaskedChanged.InvokeAsync(!IsMasked); @@ -104,7 +137,8 @@ private void ToggleMenuOpen() _isMenuOpen = !_isMenuOpen; } - private async Task OpenTextVisualizerAsync() + [JSInvokable] + public async Task OpenTextVisualizerAsync() { var parameters = new DialogParameters { @@ -120,10 +154,4 @@ private async Task OpenTextVisualizerAsync() await DialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(Value!), parameters); } - -#pragma warning disable CA1822 - private void Test(MenuChangeEventArgs args) -#pragma warning restore CA1822 - { - } } diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index f86f04d492d..de72df2aa4a 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -299,3 +299,19 @@ window.listenToWindowResize = function(dotnetHelper) { window.addEventListener('resize', throttledResizeListener); } + +window.registerOpenTextVisualizerOnClick = function(menuItemId, gridValue) { + const onClickListener = function () { + gridValue.invokeMethodAsync('OpenTextVisualizerAsync'); + } + + document.getElementById(menuItemId).addEventListener('onclick', onClickListener); + + return { + onClickListener: onClickListener, + } +} + +window.unregisterOpenTextVisualizerOnClick = function (menuItemId, onClickListener) { + document.getElementById(menuItemId).removeEventListener('onclick', onClickListener); +} From eebf7a49da3e6c6ea1791c279f09a84dbee0fb30 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 22 Jul 2024 17:29:56 -0400 Subject: [PATCH 04/25] Style dialog, work around fluentui onclick issue for FluentMenuItem --- .../Components/Controls/GridValue.razor | 8 +- .../Components/Controls/GridValue.razor.cs | 49 --- .../Dialogs/TextVisualizerDialog.razor | 44 ++- .../Dialogs/TextVisualizerDialog.razor.cs | 105 ++++++ .../Components/Layout/MainLayout.razor.cs | 35 +- .../LogMessageColumnDisplay.razor | 2 +- .../Extensions/FluentUIExtensions.cs | 18 +- .../Model/TextVisualizerDialogViewModel.cs | 2 +- .../Resources/Dialogs.Designer.cs | 298 ++++++------------ src/Aspire.Dashboard/Resources/Dialogs.resx | 68 ++-- .../Resources/xlf/Dialogs.cs.xlf | 20 ++ .../Resources/xlf/Dialogs.de.xlf | 20 ++ .../Resources/xlf/Dialogs.es.xlf | 20 ++ .../Resources/xlf/Dialogs.fr.xlf | 20 ++ .../Resources/xlf/Dialogs.it.xlf | 20 ++ .../Resources/xlf/Dialogs.ja.xlf | 20 ++ .../Resources/xlf/Dialogs.ko.xlf | 20 ++ .../Resources/xlf/Dialogs.pl.xlf | 20 ++ .../Resources/xlf/Dialogs.pt-BR.xlf | 20 ++ .../Resources/xlf/Dialogs.ru.xlf | 20 ++ .../Resources/xlf/Dialogs.tr.xlf | 20 ++ .../Resources/xlf/Dialogs.zh-Hans.xlf | 20 ++ .../Resources/xlf/Dialogs.zh-Hant.xlf | 20 ++ src/Aspire.Dashboard/wwwroot/js/app.js | 18 +- 24 files changed, 612 insertions(+), 295 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index 9c2b1a43ec6..c52745b8349 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -51,10 +51,10 @@ - + + AdditionalAttributes="@FluentUiExtensions.GetClipboardCopyAdditionalAttributes(ValueToCopy ?? Value, PreCopyToolTip, PostCopyToolTip, uncapturedCopyAttributes)"> - + diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs index 887729b9174..b36e08b5bbf 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor.cs @@ -1,11 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Aspire.Dashboard.Components.Dialogs; using Aspire.Dashboard.Components.Resize; -using Aspire.Dashboard.Model; using Aspire.Dashboard.Resources; -using Aspire.Dashboard.Utils; using Microsoft.AspNetCore.Components; using Microsoft.FluentUI.AspNetCore.Components; using Microsoft.JSInterop; @@ -81,10 +78,7 @@ public partial class GridValue private readonly Icon _unmaskIcon = new Icons.Regular.Size16.Eye(); private readonly string _copyId = $"copy-{Guid.NewGuid():N}"; private readonly string _menuAnchorId = $"menu-{Guid.NewGuid():N}"; - private readonly string _openVisualizerId = $"open-visualizer-{Guid.NewGuid():N}"; private bool _isMenuOpen; - private IJSObjectReference? _onClickHandler; - private DotNetObjectReference? _thisReference; protected override void OnInitialized() { @@ -92,31 +86,6 @@ protected override void OnInitialized() PostCopyToolTip = Loc[nameof(ControlsStrings.GridValueCopied)]; } - private async Task OnOpenChangedAsync() - { - if (_isMenuOpen) - { - _thisReference?.Dispose(); - - try - { - await JS.InvokeVoidAsync("window.unregisterGlobalKeydownListener", _openVisualizerId, _onClickHandler); - } - catch (JSDisconnectedException) - { - // Per https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0#javascript-interop-calls-without-a-circuit - // this is one of the calls that will fail if the circuit is disconnected, and we just need to catch the exception so it doesn't pollute the logs - } - - await JSInteropHelpers.SafeDisposeAsync(_onClickHandler); - } - else - { - _thisReference = DotNetObjectReference.Create(this); - _onClickHandler = await JS.InvokeAsync("window.registerOpenTextVisualizerOnClick", _openVisualizerId, _thisReference); - } - } - private string GetContainerClass() => EnableMasking ? "container masking-enabled" : "container"; private async Task ToggleMaskStateAsync() @@ -136,22 +105,4 @@ private void ToggleMenuOpen() { _isMenuOpen = !_isMenuOpen; } - - [JSInvokable] - public async Task OpenTextVisualizerAsync() - { - var parameters = new DialogParameters - { - Title = ValueDescription, - PrimaryActionEnabled = false, - SecondaryActionEnabled = false, - Width = ViewportInformation.IsDesktop ? "60vw" : "100vw", - Height = ViewportInformation.IsDesktop ? "60vh" : "100vh", - TrapFocus = true, - Modal = true, - PreventScroll = true - }; - - await DialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(Value!), parameters); - } } diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index 90054f34ae2..304d07b6a30 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -1,7 +1,49 @@ @using Aspire.Dashboard.Model +@using Aspire.Dashboard.Resources + +@inject IStringLocalizer Loc @implements IDialogContentComponent -@Content.Text + + + + + @Content.Description + + + + + + + + @foreach (var option in _options) + { + @option.Name + } + + + + + + + +
+        @_formattedText
+    
+
+ + @code { [Parameter, EditorRequired] diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index aaf3e133275..fc871a36745 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -1,11 +1,116 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text; +using System.Text.Json; +using System.Xml; +using System.Xml.Linq; +using Aspire.Dashboard.Model.Otlp; using Microsoft.AspNetCore.Components; namespace Aspire.Dashboard.Components.Dialogs; public partial class TextVisualizerDialog : ComponentBase { + private const string XmlFormat = "xml"; + private const string JsonFormat = "json"; + private const string PlaintextFormat = "text"; + + private List> _options = null!; + private string _selectedOption = null!; + + private string _formattedText = string.Empty; + + private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; + private bool _isSelectFormatPopupOpen; + + protected override void OnInitialized() + { + _options = + [ + new SelectViewModel { Id = PlaintextFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogPlaintextFormat)] }, + new SelectViewModel { Id = JsonFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogJsonFormat)] }, + new SelectViewModel { Id = XmlFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogXmlFormat)] }, + ]; + } + + protected override void OnParametersSet() + { + // We don't know what format the string is in, but we can guess + if (TryFormatXml()) + { + _selectedOption = XmlFormat; + return; + } + + if (TryFormatJson()) + { + _selectedOption = JsonFormat; + return; + } + + _selectedOption = PlaintextFormat; + _formattedText = Content.Text; + } + + private bool TryFormatXml() + { + try + { + _formattedText = XElement.Parse(Content.Text).ToString(); + return true; + } + catch (XmlException) + { + // If the XML is invalid, just show the original text + _formattedText = Content.Text; + return false; + } + } + + private bool TryFormatJson() + { + try + { + using var doc = JsonDocument.Parse( + Content.Text, + new JsonDocumentOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip + } + ); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, new JsonWriterOptions { Indented = true }); + doc.WriteTo(utf8JsonWriter); + utf8JsonWriter.Flush(); + + _formattedText = Encoding.Default.GetString(memoryStream.ToArray()); + return true; + } + catch (JsonException) + { + // If the JSON is invalid, just show the original text + _formattedText = Content.Text; + return false; + } + } + + private void OnFormatOptionChanged() + { + if (_selectedOption == XmlFormat) + { + TryFormatXml(); + } + else if (_selectedOption == JsonFormat) + { + TryFormatJson(); + } + else + { + _formattedText = Content.Text; + } + } } diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index 3fddc574db0..1999efde999 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -22,7 +22,9 @@ public partial class MainLayout : IGlobalKeydownListener, IAsyncDisposable private IDisposable? _locationChangingRegistration; private IJSObjectReference? _jsModule; private IJSObjectReference? _keyboardHandlers; + private IJSObjectReference? _textVisualizerHandler; private DotNetObjectReference? _shortcutManagerReference; + private DotNetObjectReference? _layoutReference; private IDialogReference? _openPageDialog; private const string SettingsDialogId = "SettingsDialog"; @@ -124,7 +126,9 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { _jsModule = await JS.InvokeAsync("import", "/js/app-theme.js"); _shortcutManagerReference = DotNetObjectReference.Create(ShortcutManager); + _layoutReference = DotNetObjectReference.Create(this); _keyboardHandlers = await JS.InvokeAsync("window.registerGlobalKeydownListener", _shortcutManagerReference); + _textVisualizerHandler = await JS.InvokeAsync("window.registerOpenTextVisualizerOnClick", _layoutReference); ShortcutManager.AddGlobalKeydownListener(this); } } @@ -248,25 +252,46 @@ private void CloseMobileNavMenu() StateHasChanged(); } + [JSInvokable] + public async Task OpenTextVisualizerAsync(string value, string valueDescription) + { + var parameters = new DialogParameters + { + Title = valueDescription, + Width = ViewportInformation.IsDesktop ? "60vw" : "100vw", + TrapFocus = true, + Modal = true, + PreventScroll = true, + }; + + await DialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(value, valueDescription), parameters); + } + public async ValueTask DisposeAsync() { _shortcutManagerReference?.Dispose(); + _layoutReference?.Dispose(); _themeChangedSubscription?.Dispose(); _locationChangingRegistration?.Dispose(); ShortcutManager.RemoveGlobalKeydownListener(this); - if (_keyboardHandlers is { } h) + try { - try + if (_keyboardHandlers is { } h) { await JS.InvokeVoidAsync("window.unregisterGlobalKeydownListener", h); } - catch (JSDisconnectedException) + + if (_textVisualizerHandler is not null) { - // Per https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0#javascript-interop-calls-without-a-circuit - // this is one of the calls that will fail if the circuit is disconnected, and we just need to catch the exception so it doesn't pollute the logs + await JS.InvokeVoidAsync("window.unregisterOpenTextVisualizerOnClick", _textVisualizerHandler); } } + catch (JSDisconnectedException) + { + // Per https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0#javascript-interop-calls-without-a-circuit + // this is one of the calls that will fail if the circuit is disconnected, and we just need to catch the exception so it doesn't pollute the logs + } await JSInteropHelpers.SafeDisposeAsync(_jsModule); await JSInteropHelpers.SafeDisposeAsync(_keyboardHandlers); diff --git a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor index c6293165cab..76191764d72 100644 --- a/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor +++ b/src/Aspire.Dashboard/Components/ResourcesGridColumns/LogMessageColumnDisplay.razor @@ -38,7 +38,7 @@ + AdditionalAttributes="@FluentUiExtensions.GetClipboardCopyAdditionalAttributes(_errorInfo, ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)].ToString(), ControlsStringsLoc[nameof(ControlsStrings.GridValueCopied)].ToString())"> @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] diff --git a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs index 9c6d33bf856..6c503e3b9e9 100644 --- a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs +++ b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs @@ -3,7 +3,7 @@ namespace Aspire.Dashboard.Extensions; -internal static class FluentUIExtensions +internal static class FluentUiExtensions { public static Dictionary GetClipboardCopyAdditionalAttributes(string? text, string? precopy, string? postcopy, params (string Attribute, object Value)[] additionalAttributes) { @@ -25,4 +25,20 @@ public static Dictionary GetClipboardCopyAdditionalAttributes(st return attributes; } + + public static Dictionary GetOpenTextVisualizerAdditionalAttributes(string textValue, string textValueDescription, params (string Attribute, object Value)[] additionalAttributes) + { + var attributes = new Dictionary + { + { "data-textvisualizer-text", textValue }, + { "data-textvisualizer-description", textValueDescription } + }; + + foreach (var (attribute, value) in additionalAttributes) + { + attributes.Add(attribute, value); + } + + return attributes; + } } diff --git a/src/Aspire.Dashboard/Model/TextVisualizerDialogViewModel.cs b/src/Aspire.Dashboard/Model/TextVisualizerDialogViewModel.cs index b8506797c7c..ff4fd8d68db 100644 --- a/src/Aspire.Dashboard/Model/TextVisualizerDialogViewModel.cs +++ b/src/Aspire.Dashboard/Model/TextVisualizerDialogViewModel.cs @@ -3,4 +3,4 @@ namespace Aspire.Dashboard.Model; -public record TextVisualizerDialogViewModel(string Text); +public record TextVisualizerDialogViewModel(string Text, string Description); diff --git a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs index e06f38aba6a..fb92002382d 100644 --- a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Dialogs { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Dialogs() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.Dialogs", typeof(Dialogs).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.Dialogs", typeof(Dialogs).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,336 +45,249 @@ internal Dialogs() { } } - /// - /// Looks up a localized string similar to Close. - /// - public static string ExemplarsDialogCloseButtonText { + public static string FilterDialogFieldPlaceholder { get { - return ResourceManager.GetString("ExemplarsDialogCloseButtonText", resourceCulture); + return ResourceManager.GetString("FilterDialogFieldPlaceholder", resourceCulture); } } - /// - /// Looks up a localized string similar to Details. - /// - public static string ExemplarsDialogDetailsColumnHeader { + public static string FilterDialogTextValuePlaceholder { get { - return ResourceManager.GetString("ExemplarsDialogDetailsColumnHeader", resourceCulture); + return ResourceManager.GetString("FilterDialogTextValuePlaceholder", resourceCulture); } } - /// - /// Looks up a localized string similar to Timestamp. - /// - public static string ExemplarsDialogTimestampColumnHeader { + public static string FilterDialogCancelButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTimestampColumnHeader", resourceCulture); + return ResourceManager.GetString("FilterDialogCancelButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Exemplars. - /// - public static string ExemplarsDialogTitle { + public static string FilterDialogApplyFilterButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTitle", resourceCulture); + return ResourceManager.GetString("FilterDialogApplyFilterButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string ExemplarsDialogTrace { + public static string FilterDialogRemoveFilterButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTrace", resourceCulture); + return ResourceManager.GetString("FilterDialogRemoveFilterButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string ExemplarsDialogTraceColumnHeader { + public static string SettingsDialogSystemTheme { get { - return ResourceManager.GetString("ExemplarsDialogTraceColumnHeader", resourceCulture); + return ResourceManager.GetString("SettingsDialogSystemTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string ExemplarsDialogValueColumnHeader { + public static string SettingsDialogLightTheme { get { - return ResourceManager.GetString("ExemplarsDialogValueColumnHeader", resourceCulture); + return ResourceManager.GetString("SettingsDialogLightTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Apply filter. - /// - public static string FilterDialogApplyFilterButtonText { + public static string SettingsDialogDarkTheme { get { - return ResourceManager.GetString("FilterDialogApplyFilterButtonText", resourceCulture); + return ResourceManager.GetString("SettingsDialogDarkTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Cancel. - /// - public static string FilterDialogCancelButtonText { + public static string SettingsDialogTheme { get { - return ResourceManager.GetString("FilterDialogCancelButtonText", resourceCulture); + return ResourceManager.GetString("SettingsDialogTheme", resourceCulture); + } + } + + public static string SettingsDialogVersion { + get { + return ResourceManager.GetString("SettingsDialogVersion", resourceCulture); } } - /// - /// Looks up a localized string similar to Select a filter condition. - /// public static string FilterDialogConditionSelectLabel { get { return ResourceManager.GetString("FilterDialogConditionSelectLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Field. - /// - public static string FilterDialogFieldPlaceholder { + public static string HelpDialogGetHelpLinkText { get { - return ResourceManager.GetString("FilterDialogFieldPlaceholder", resourceCulture); + return ResourceManager.GetString("HelpDialogGetHelpLinkText", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove filter. - /// - public static string FilterDialogRemoveFilterButtonText { + public static string HelpDialogCategoryPanels { get { - return ResourceManager.GetString("FilterDialogRemoveFilterButtonText", resourceCulture); + return ResourceManager.GetString("HelpDialogCategoryPanels", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string FilterDialogTextValuePlaceholder { + public static string HelpDialogCategoryPageNavigation { get { - return ResourceManager.GetString("FilterDialogTextValuePlaceholder", resourceCulture); + return ResourceManager.GetString("HelpDialogCategoryPageNavigation", resourceCulture); } } - /// - /// Looks up a localized string similar to Site-wide navigation. - /// public static string HelpDialogCategoryNavigation { get { return ResourceManager.GetString("HelpDialogCategoryNavigation", resourceCulture); } } - /// - /// Looks up a localized string similar to Page navigation. - /// - public static string HelpDialogCategoryPageNavigation { + public static string HelpDialogIncreasePanelSize { get { - return ResourceManager.GetString("HelpDialogCategoryPageNavigation", resourceCulture); + return ResourceManager.GetString("HelpDialogIncreasePanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Panels. - /// - public static string HelpDialogCategoryPanels { + public static string HelpDialogDecreasePanelSize { get { - return ResourceManager.GetString("HelpDialogCategoryPanels", resourceCulture); + return ResourceManager.GetString("HelpDialogDecreasePanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Decrease panel size. - /// - public static string HelpDialogDecreasePanelSize { + public static string HelpDialogResetPanelSize { get { - return ResourceManager.GetString("HelpDialogDecreasePanelSize", resourceCulture); + return ResourceManager.GetString("HelpDialogResetPanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Microsoft Learn documentation. - /// - public static string HelpDialogGetHelpLinkText { + public static string HelpDialogTogglePanelOrientation { get { - return ResourceManager.GetString("HelpDialogGetHelpLinkText", resourceCulture); + return ResourceManager.GetString("HelpDialogTogglePanelOrientation", resourceCulture); + } + } + + public static string HelpDialogTogglePanelOpen { + get { + return ResourceManager.GetString("HelpDialogTogglePanelOpen", resourceCulture); + } + } + + public static string HelpDialogGoToResources { + get { + return ResourceManager.GetString("HelpDialogGoToResources", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Console Logs. - /// public static string HelpDialogGoToConsoleLogs { get { return ResourceManager.GetString("HelpDialogGoToConsoleLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Help. - /// - public static string HelpDialogGoToHelp { + public static string HelpDialogGoToStructuredLogs { get { - return ResourceManager.GetString("HelpDialogGoToHelp", resourceCulture); + return ResourceManager.GetString("HelpDialogGoToStructuredLogs", resourceCulture); + } + } + + public static string HelpDialogGoToTraces { + get { + return ResourceManager.GetString("HelpDialogGoToTraces", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Metrics. - /// public static string HelpDialogGoToMetrics { get { return ResourceManager.GetString("HelpDialogGoToMetrics", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Resources. - /// - public static string HelpDialogGoToResources { + public static string HelpDialogGoToHelp { get { - return ResourceManager.GetString("HelpDialogGoToResources", resourceCulture); + return ResourceManager.GetString("HelpDialogGoToHelp", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Settings. - /// public static string HelpDialogGoToSettings { get { return ResourceManager.GetString("HelpDialogGoToSettings", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Structured Logs. - /// - public static string HelpDialogGoToStructuredLogs { + public static string HelpDialogKeyboardShortcutsTitle { get { - return ResourceManager.GetString("HelpDialogGoToStructuredLogs", resourceCulture); + return ResourceManager.GetString("HelpDialogKeyboardShortcutsTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Traces. - /// - public static string HelpDialogGoToTraces { + public static string ExemplarsDialogCloseButtonText { get { - return ResourceManager.GetString("HelpDialogGoToTraces", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogCloseButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Increase panel size. - /// - public static string HelpDialogIncreasePanelSize { + public static string ExemplarsDialogTitle { get { - return ResourceManager.GetString("HelpDialogIncreasePanelSize", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Keyboard Shortcuts. - /// - public static string HelpDialogKeyboardShortcutsTitle { + public static string ExemplarsDialogTraceColumnHeader { get { - return ResourceManager.GetString("HelpDialogKeyboardShortcutsTitle", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTraceColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Reset panel sizes. - /// - public static string HelpDialogResetPanelSize { + public static string ExemplarsDialogTimestampColumnHeader { get { - return ResourceManager.GetString("HelpDialogResetPanelSize", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTimestampColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Close panel. - /// - public static string HelpDialogTogglePanelOpen { + public static string ExemplarsDialogValueColumnHeader { get { - return ResourceManager.GetString("HelpDialogTogglePanelOpen", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogValueColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Toggle panel orientation. - /// - public static string HelpDialogTogglePanelOrientation { + public static string ExemplarsDialogDetailsColumnHeader { get { - return ResourceManager.GetString("HelpDialogTogglePanelOrientation", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogDetailsColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Cancel. - /// - public static string OpenTraceDialogCancelButtonText { + public static string ExemplarsDialogTrace { get { - return ResourceManager.GetString("OpenTraceDialogCancelButtonText", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTrace", resourceCulture); } } - /// - /// Looks up a localized string similar to Waiting for trace {0} to load.... - /// public static string OpenTraceDialogMessage { get { return ResourceManager.GetString("OpenTraceDialogMessage", resourceCulture); } } - /// - /// Looks up a localized string similar to Dark. - /// - public static string SettingsDialogDarkTheme { + public static string OpenTraceDialogCancelButtonText { get { - return ResourceManager.GetString("SettingsDialogDarkTheme", resourceCulture); + return ResourceManager.GetString("OpenTraceDialogCancelButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Light. - /// - public static string SettingsDialogLightTheme { + public static string TextVisualizerDialogPlaintextFormat { get { - return ResourceManager.GetString("SettingsDialogLightTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogPlaintextFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to System. - /// - public static string SettingsDialogSystemTheme { + public static string TextVisualizerDialogJsonFormat { get { - return ResourceManager.GetString("SettingsDialogSystemTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogJsonFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to Theme. - /// - public static string SettingsDialogTheme { + public static string TextVisualizerDialogXmlFormat { get { - return ResourceManager.GetString("SettingsDialogTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogXmlFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to Version: {0}. - /// - public static string SettingsDialogVersion { + public static string TextVisualizerSelectFormatType { get { - return ResourceManager.GetString("SettingsDialogVersion", resourceCulture); + return ResourceManager.GetString("TextVisualizerSelectFormatType", resourceCulture); } } } diff --git a/src/Aspire.Dashboard/Resources/Dialogs.resx b/src/Aspire.Dashboard/Resources/Dialogs.resx index 3aee27774b5..61abf0c2154 100644 --- a/src/Aspire.Dashboard/Resources/Dialogs.resx +++ b/src/Aspire.Dashboard/Resources/Dialogs.resx @@ -1,17 +1,17 @@  - @@ -230,4 +230,16 @@ Cancel - \ No newline at end of file + + Plain-text + + + Format JSON + + + Format XML + + + Select format + + diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf index 5abc00668f1..bcf82a346e9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf @@ -187,6 +187,26 @@ Verze: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf index 95d7603bc21..21620f58139 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf @@ -187,6 +187,26 @@ Version: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf index 2a7e0053f45..1dbeaacf589 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf @@ -187,6 +187,26 @@ Versión: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf index f191d0be8ed..aca1d600a46 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf @@ -187,6 +187,26 @@ Version : {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf index 1bec0d5e590..efc6199b4a9 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf @@ -187,6 +187,26 @@ Versione: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf index 98ac103e983..0f3a0179c56 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf @@ -187,6 +187,26 @@ バージョン: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf index 8648776cd87..714b0d771e1 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf @@ -187,6 +187,26 @@ 버전: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf index c2fbb020df0..fc70f1308ab 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf @@ -187,6 +187,26 @@ Wersja: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf index c028903d018..ca31c17b378 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf @@ -187,6 +187,26 @@ Versão: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf index 345a4f246c7..37ba8e93ac5 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf @@ -187,6 +187,26 @@ Версия: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf index 703a81b63a5..a0527992d53 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf @@ -187,6 +187,26 @@ Sürüm: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf index a933749ee1e..160218f7946 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf @@ -187,6 +187,26 @@ 版本: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf index 0ad0fec1792..975d1a9e12f 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf @@ -187,6 +187,26 @@ 版本: {0} {0} is the dashboard version string + + Format JSON + Format JSON + + + + Plain-text + Plain-text + + + + Format XML + Format XML + + + + Select format + Select format + + \ No newline at end of file diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index de72df2aa4a..b551f91f6ca 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -300,18 +300,24 @@ window.listenToWindowResize = function(dotnetHelper) { window.addEventListener('resize', throttledResizeListener); } -window.registerOpenTextVisualizerOnClick = function(menuItemId, gridValue) { - const onClickListener = function () { - gridValue.invokeMethodAsync('OpenTextVisualizerAsync'); +window.registerOpenTextVisualizerOnClick = function(layout) { + const onClickListener = function (e) { + const text = e.target.getAttribute("data-textvisualizer-text"); + const description = e.target.getAttribute("data-textvisualizer-description"); + + if (e.target.tagName.toLowerCase() === "fluent-menu-item" && text && description) { + e.stopPropagation(); + layout.invokeMethodAsync("OpenTextVisualizerAsync", text, description); + } } - document.getElementById(menuItemId).addEventListener('onclick', onClickListener); + document.addEventListener('click', onClickListener); return { onClickListener: onClickListener, } } -window.unregisterOpenTextVisualizerOnClick = function (menuItemId, onClickListener) { - document.getElementById(menuItemId).removeEventListener('onclick', onClickListener); +window.unregisterOpenTextVisualizerOnClick = function (listener) { + document.removeEventListener('click', listener); } From 86c1a5cc4130642019ab87b8ab3ea1fc579cc71f Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 22 Jul 2024 17:42:44 -0400 Subject: [PATCH 05/25] Remove hardcoded string --- src/Aspire.Dashboard/Components/Controls/GridValue.razor | 3 ++- src/Aspire.Dashboard/Resources/Dialogs.Designer.cs | 6 ++++++ src/Aspire.Dashboard/Resources/Dialogs.resx | 3 +++ src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf | 5 +++++ src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf | 5 +++++ 16 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index c52745b8349..e4af86ab772 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -1,6 +1,7 @@ @using Aspire.Dashboard.Extensions @using Aspire.Dashboard.Resources @inject IStringLocalizer Loc +@inject IStringLocalizer DialogsLoc
@if (EnableMasking && IsMasked) @@ -69,6 +70,6 @@ - Open in text visualizer + @DialogsLoc[nameof(Dialogs.OpenInTextVisualizer)] diff --git a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs index fb92002382d..a86250aff5e 100644 --- a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs @@ -290,5 +290,11 @@ public static string TextVisualizerSelectFormatType { return ResourceManager.GetString("TextVisualizerSelectFormatType", resourceCulture); } } + + public static string OpenInTextVisualizer { + get { + return ResourceManager.GetString("OpenInTextVisualizer", resourceCulture); + } + } } } diff --git a/src/Aspire.Dashboard/Resources/Dialogs.resx b/src/Aspire.Dashboard/Resources/Dialogs.resx index 61abf0c2154..e6a0b3151ba 100644 --- a/src/Aspire.Dashboard/Resources/Dialogs.resx +++ b/src/Aspire.Dashboard/Resources/Dialogs.resx @@ -242,4 +242,7 @@ Select format + + Open in text visualizer + diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf index bcf82a346e9..55eac056a37 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf @@ -152,6 +152,11 @@ Přepnout orientaci panelu + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf index 21620f58139..a7656bee51e 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf @@ -152,6 +152,11 @@ Bereichsausrichtung umschalten + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf index 1dbeaacf589..e38cf60b191 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf @@ -152,6 +152,11 @@ Alternar orientación del panel + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf index aca1d600a46..92400a2bdb7 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf @@ -152,6 +152,11 @@ Activer/désactiver l’orientation du panneau + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf index efc6199b4a9..0c4e33d7768 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf @@ -152,6 +152,11 @@ Attiva/Disattiva orientamento del pannello + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf index 0f3a0179c56..08994ec4fea 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf @@ -152,6 +152,11 @@ パネルの向きを切り替える + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf index 714b0d771e1..7fdfae90e8a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf @@ -152,6 +152,11 @@ 패널 방향 전환 + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf index fc70f1308ab..6c907056afe 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf @@ -152,6 +152,11 @@ Przełącz orientację panelu + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf index ca31c17b378..3271dec0d60 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf @@ -152,6 +152,11 @@ Alternar orientação do painel + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf index 37ba8e93ac5..bef7ca4093c 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf @@ -152,6 +152,11 @@ Переключить ориентацию панели + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf index a0527992d53..8584d32e729 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf @@ -152,6 +152,11 @@ Panelin yönünü değiştir + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf index 160218f7946..3b3bac0e6ff 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf @@ -152,6 +152,11 @@ 切换面板方向 + + Open in text visualizer + Open in text visualizer + + Cancel Cancel diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf index 975d1a9e12f..52d97e65eca 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf @@ -152,6 +152,11 @@ 切換面板方向 + + Open in text visualizer + Open in text visualizer + + Cancel Cancel From 633250ae79f716841ece2a62b08af61b4747fbff Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Tue, 23 Jul 2024 12:19:52 -0400 Subject: [PATCH 06/25] Update unformatted name, use JsonSerializer.Serialize, use key comparer for dictionaries, switch button appearance and icon --- .../Components/Controls/GridValue.razor | 4 ++-- .../Components/Dialogs/TextVisualizerDialog.razor | 4 ++-- .../Dialogs/TextVisualizerDialog.razor.cs | 12 ++++-------- .../LogMessageColumnDisplay.razor | 2 +- .../Extensions/FluentUIExtensions.cs | 15 ++++++++++++--- src/Aspire.Dashboard/Resources/Dialogs.resx | 2 +- src/Aspire.Dashboard/Resources/xlf/Dialogs.cs.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf | 4 ++-- .../Resources/xlf/Dialogs.pt-BR.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf | 4 ++-- src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf | 4 ++-- .../Resources/xlf/Dialogs.zh-Hans.xlf | 4 ++-- .../Resources/xlf/Dialogs.zh-Hant.xlf | 4 ++-- 19 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index e4af86ab772..ada88e8fdea 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -55,7 +55,7 @@ + AdditionalAttributes="@FluentUIExtensions.GetClipboardCopyAdditionalAttributes(ValueToCopy ?? Value, PreCopyToolTip, PostCopyToolTip, uncapturedCopyAttributes)"> - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf index a7656bee51e..1d1be1aecbb 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.de.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf index e38cf60b191..69aa0bd8bfa 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.es.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf index 92400a2bdb7..36cc835555a 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.fr.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf index 0c4e33d7768..ed54d58bc82 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.it.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf index 08994ec4fea..f19377206a8 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ja.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf index 7fdfae90e8a..68c227f7790 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ko.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf index 6c907056afe..3eb52440d27 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pl.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf index 3271dec0d60..ba0b03fdce6 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.pt-BR.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf index bef7ca4093c..0321ee2fb39 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.ru.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf index 8584d32e729..05a32ebaa94 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.tr.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf index 3b3bac0e6ff..f84a5926016 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hans.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted diff --git a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf index 52d97e65eca..e64326af044 100644 --- a/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf +++ b/src/Aspire.Dashboard/Resources/xlf/Dialogs.zh-Hant.xlf @@ -198,8 +198,8 @@ - Plain-text - Plain-text + Unformatted + Unformatted From 2b9ebab48d94c61e812122b5e5e8d2d1cd719b8b Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Tue, 23 Jul 2024 17:20:16 -0400 Subject: [PATCH 07/25] Display dialog like in console logs --- .../Components/Controls/GridValue.razor | 2 +- .../Components/Controls/LogViewer.razor | 14 +-- .../Components/Controls/LogViewer.razor.css | 101 ++---------------- .../Dialogs/TextVisualizerDialog.razor | 23 +++- .../Dialogs/TextVisualizerDialog.razor.cs | 49 +++++---- .../Dialogs/TextVisualizerDialog.razor.css | 3 + .../Components/Layout/MainLayout.razor.cs | 2 + .../Extensions/FluentUIExtensions.cs | 2 +- src/Aspire.Dashboard/wwwroot/css/app.css | 87 +++++++++++++++ src/Aspire.Dashboard/wwwroot/js/app.js | 10 +- 10 files changed, 165 insertions(+), 128 deletions(-) create mode 100644 src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index ada88e8fdea..716dce75d3f 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -52,7 +52,7 @@
- + diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 72c6743a9f4..5a8fa26dadf 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -6,14 +6,14 @@ @inject IJSRuntime JS @implements IAsyncDisposable -
-
+
+
-
-
- - @context.LineNumber - +
+
+ + @context.LineNumber + @if (context.Timestamp is { } timestamp) { @GetDisplayTimestamp(timestamp) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css index 97f2726d3ba..207a9da9a3f 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css @@ -1,117 +1,36 @@ -.log-overflow { - --console-theme-black: #0C0C0C; - --console-theme-blue: #0037DA; - --console-theme-cyan: #3A96DD; - --console-theme-green: #13A10E; - --console-theme-magenta: #CD13E8; - --console-theme-bg-red: #F80F24; - --console-theme-fg-red: #C50F1F; - --console-theme-white: #CCCCCC; - --console-theme-yellow: #C19C00; - - --console-theme-bright-black: #767676; - --console-theme-bright-blue: #3B78FF; - --console-theme-bright-cyan: #61D6D6; - --console-theme-bright-green: #16C60C; - --console-theme-bright-magenta: #DA01FA; - --console-theme-bright-red: #E74856; - --console-theme-bright-white: #F2F2F2; - --console-theme-bright-yellow: #F9F1A5; - - --line-number-color: #848484; - --timestamp-color: var(--line-number-color); - --console-background-color: var(--console-theme-black); - --console-background-color-hover: #1D1D1D; - --console-font-color: var(--console-theme-white); - - height: 100%; - width: 100%; - overflow: auto; +::deep .console-overflow { background-color: var(--console-background-color); } -::deep .log-container { +::deep .console-container { background: var(--console-background-color); color: var(--console-font-color); - font-family: 'Cascadia Mono', Consolas, monospace; - font-size: 13px; - margin: 16px 0 0 0; - padding-bottom: 24px; - line-height: 20px; - overflow: visible; - display: flex; - flex-direction: column; - width: 100%; } -::deep .line-row-container { - width: 100%; - overflow: hidden; -} - -::deep .line-row { - cursor: text; - padding: 0 12px 0 12px; - white-space: pre-wrap; - - display: flex; - flex-direction: row; - flex-grow: 1; -} - -::deep .line-row:hover { +::deep .console-line-row:hover { background-color: var(--console-background-color-hover); } -::deep .line-area { - flex-grow: 1; - justify-content: flex-start; - display: flex; - flex-direction: row; -} - -::deep .line-number { - padding-left: 10px; - min-width: 43px; - text-align: right; - align-self: flex-start; - flex-shrink: 0; - color: var(--line-number-color); - user-select: none; - cursor: default; -} - -::deep .content { - word-break: break-all; - margin-left: 20px; - position: relative; - margin-right: 6px; - user-select: text; - cursor: text; - white-space: pre-wrap; - overflow-wrap: anywhere; -} - -::deep .content .timestamp { +::deep .log-content .timestamp { color: var(--timestamp-color); } -::deep .content a, -::deep .content a:active, -::deep .content a:visited { +::deep .log-content a, +::deep .log-content a:active, +::deep .log-content a:visited { color: var(--console-font-color); text-decoration: none; } -::deep .content a:hover { +::deep .log-content a:hover { text-decoration: underline; } -::deep .content > fluent-badge { +::deep .log-content > fluent-badge { user-select: none; } -::deep .content > .timestamp + fluent-badge { +::deep .log-content > .timestamp + fluent-badge { margin-left: 1ch; } diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index 3fd45fb253d..eaed4b8c130 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -13,7 +13,7 @@ @foreach (var option in _options) { - @option.Name + @option.Name } @@ -38,9 +38,22 @@ -
-        @_formattedText
-    
+
+
+ +
+
+ + @context.LineNumber + + @((MarkupString)(context.Content ?? string.Empty)) + + +
+
+
+
+
diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 7884d45aa5c..49b3183cf02 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; +using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Otlp; using Microsoft.AspNetCore.Components; @@ -14,44 +16,53 @@ public partial class TextVisualizerDialog : ComponentBase private const string XmlFormat = "xml"; private const string JsonFormat = "json"; private const string PlaintextFormat = "text"; + private static readonly JsonSerializerOptions s_serializerOptions = new() { WriteIndented = true }; private List> _options = null!; + private readonly HashSet _enabledOptions = []; private string _selectedOption = null!; - private string _formattedText = string.Empty; private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; private bool _isSelectFormatPopupOpen; - private static readonly JsonSerializerOptions s_serializerOptions = new() { WriteIndented = true }; - - protected override void OnInitialized() + protected override void OnParametersSet() { - _options = - [ + _enabledOptions.Clear(); + _enabledOptions.Add(PlaintextFormat); + + _options = [ new SelectViewModel { Id = PlaintextFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogPlaintextFormat)] }, new SelectViewModel { Id = JsonFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogJsonFormat)] }, - new SelectViewModel { Id = XmlFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogXmlFormat)] }, + new SelectViewModel { Id = XmlFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogXmlFormat)] } ]; - } - protected override void OnParametersSet() - { - // We don't know what format the string is in, but we can guess - if (TryFormatXml()) + if (TryFormatJson()) + { + _selectedOption = JsonFormat; + _enabledOptions.Add(JsonFormat); + } + else if (TryFormatXml()) { _selectedOption = XmlFormat; - return; + _enabledOptions.Add(XmlFormat); + } + else + { + _selectedOption = PlaintextFormat; + _formattedText = Content.Text; } + } - if (TryFormatJson()) + private ICollection GetLines() + { + var lines = Regex.Split(_formattedText, "(\r\n|\n)", RegexOptions.Compiled).ToList(); + if (lines.Count > 0 && lines[0].Length == 0) { - _selectedOption = JsonFormat; - return; + lines.RemoveAt(0); } - _selectedOption = PlaintextFormat; - _formattedText = Content.Text; + return lines.Select((line, index) => new ResourceLogLine(index, line, false)).ToList(); } private bool TryFormatXml() @@ -107,6 +118,8 @@ private void OnFormatOptionChanged() { _formattedText = Content.Text; } + + _isSelectFormatPopupOpen = false; } } diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css new file mode 100644 index 00000000000..c413bc31d02 --- /dev/null +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css @@ -0,0 +1,3 @@ +::deep .text-visualizer-line-number { + user-select: none; +} diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index 1999efde999..2b13072bf68 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -259,6 +259,7 @@ public async Task OpenTextVisualizerAsync(string value, string valueDescription) { Title = valueDescription, Width = ViewportInformation.IsDesktop ? "60vw" : "100vw", + Height = ViewportInformation.IsDesktop ? "60vh" : "100vh", TrapFocus = true, Modal = true, PreventScroll = true, @@ -295,5 +296,6 @@ public async ValueTask DisposeAsync() await JSInteropHelpers.SafeDisposeAsync(_jsModule); await JSInteropHelpers.SafeDisposeAsync(_keyboardHandlers); + await JSInteropHelpers.SafeDisposeAsync(_textVisualizerHandler); } } diff --git a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs index abcd9b45c4f..ca2bd9b9d04 100644 --- a/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs +++ b/src/Aspire.Dashboard/Extensions/FluentUIExtensions.cs @@ -30,7 +30,7 @@ public static Dictionary GetOpenTextVisualizerAdditionalAttribut { var attributes = new Dictionary(AttributeKeyComparer.Instance) { - { "data-textvisualizer-text", textValue }, + { "data-text", textValue }, { "data-textvisualizer-description", textValueDescription } }; diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 630a5373b0f..08c7ebb7267 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -496,3 +496,90 @@ fluent-data-grid-cell.no-ellipsis { height: 100%; overflow: auto; } + +.log-overflow { + --console-theme-black: #0C0C0C; + --console-theme-blue: #0037DA; + --console-theme-cyan: #3A96DD; + --console-theme-green: #13A10E; + --console-theme-magenta: #CD13E8; + --console-theme-bg-red: #F80F24; + --console-theme-fg-red: #C50F1F; + --console-theme-white: #CCCCCC; + --console-theme-yellow: #C19C00; + + --console-theme-bright-black: #767676; + --console-theme-bright-blue: #3B78FF; + --console-theme-bright-cyan: #61D6D6; + --console-theme-bright-green: #16C60C; + --console-theme-bright-magenta: #DA01FA; + --console-theme-bright-red: #E74856; + --console-theme-bright-white: #F2F2F2; + --console-theme-bright-yellow: #F9F1A5; + + --line-number-color: #848484; + --timestamp-color: var(--line-number-color); + --console-background-color: var(--console-theme-black); + --console-background-color-hover: #1D1D1D; + --console-font-color: var(--console-theme-white); + + height: 100%; + width: 100%; + overflow: auto; +} + +.log-container { + font-family: 'Cascadia Mono', Consolas, monospace; + font-size: 13px; + margin: 16px 0 0 0; + padding-bottom: 24px; + line-height: 20px; + overflow: visible; + display: flex; + flex-direction: column; + width: 100%; +} + +.log-line-row-container { + width: 100%; + overflow: hidden; +} + +.log-line-row { + cursor: text; + padding: 0 12px 0 12px; + white-space: pre-wrap; + + display: flex; + flex-direction: row; + flex-grow: 1; +} + +.log-line-area { + flex-grow: 1; + justify-content: flex-start; + display: flex; + flex-direction: row; +} + +.line-number { + padding-left: 10px; + min-width: 43px; + text-align: right; + align-self: flex-start; + flex-shrink: 0; + color: var(--line-number-color); + user-select: none; + cursor: default; +} + +.log-content { + word-break: break-all; + margin-left: 20px; + position: relative; + margin-right: 6px; + user-select: text; + cursor: text; + white-space: pre-wrap; + overflow-wrap: anywhere; +} diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index b551f91f6ca..c8696b5f8e3 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -250,8 +250,8 @@ window.registerGlobalKeydownListener = function(shortcutManager) { } } -window.unregisterGlobalKeydownListener = function (keydownListener) { - window.document.removeEventListener('keydown', keydownListener); +window.unregisterGlobalKeydownListener = function (obj) { + window.document.removeEventListener('keydown', obj.keydownListener); } window.getBrowserTimeZone = function () { @@ -302,7 +302,7 @@ window.listenToWindowResize = function(dotnetHelper) { window.registerOpenTextVisualizerOnClick = function(layout) { const onClickListener = function (e) { - const text = e.target.getAttribute("data-textvisualizer-text"); + const text = e.target.getAttribute("data-text"); const description = e.target.getAttribute("data-textvisualizer-description"); if (e.target.tagName.toLowerCase() === "fluent-menu-item" && text && description) { @@ -318,6 +318,6 @@ window.registerOpenTextVisualizerOnClick = function(layout) { } } -window.unregisterOpenTextVisualizerOnClick = function (listener) { - document.removeEventListener('click', listener); +window.unregisterOpenTextVisualizerOnClick = function (obj) { + document.removeEventListener('click', obj.onClickListener); } From fa0b2eaa06f73fc059015fa8c2101f19e688d477 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 29 Jul 2024 15:35:55 -0400 Subject: [PATCH 08/25] Format based on language --- .../Components/Controls/LogViewer.razor.css | 1 + .../Dialogs/TextVisualizerDialog.razor | 78 +- .../Dialogs/TextVisualizerDialog.razor.cs | 76 +- .../Dialogs/TextVisualizerDialog.razor.css | 11 + .../Dialogs/TextVisualizerDialog.razor.js | 30 + .../Components/Layout/MainLayout.razor.cs | 4 +- .../css/highlight-11.10.0-default.min.css | 9 + src/Aspire.Dashboard/wwwroot/js/app.js | 2 +- .../wwwroot/js/highlight-11.10.0.min.js | 1232 +++++++++++++++++ 9 files changed, 1390 insertions(+), 53 deletions(-) create mode 100644 src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.js create mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-default.min.css create mode 100644 src/Aspire.Dashboard/wwwroot/js/highlight-11.10.0.min.js diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css index 207a9da9a3f..d8ca91d3251 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css @@ -5,6 +5,7 @@ ::deep .console-container { background: var(--console-background-color); color: var(--console-font-color); + height: 100%; } ::deep .console-line-row:hover { diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index eaed4b8c130..f34462347c5 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -1,7 +1,9 @@ -@using Aspire.Dashboard.Model +@using Aspire.Dashboard.Extensions +@using Aspire.Dashboard.Model @using Aspire.Dashboard.Resources @inject IStringLocalizer Loc +@inject IStringLocalizer ControlsStringsLoc @implements IDialogContentComponent @@ -11,53 +13,67 @@ @Content.Description - - - - - - @foreach (var option in _options) - { - @option.Name - } - - - +
+ + @foreach (var option in _options) + { + @option.Name + } + +
-
- +
+
- - @context.LineNumber - - @((MarkupString)(context.Content ?? string.Empty)) + + @context.LineNumber + @if (context.IsFormatted) + { + + @context.Content + + } + else + { + + @context.Content + + } -
+ + + + + + + @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] +
+ + + @code { [Parameter, EditorRequired] public required TextVisualizerDialogViewModel Content { get; set; } diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 49b3183cf02..0e18edc0ad8 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -5,26 +5,44 @@ using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; -using Aspire.Dashboard.Model; using Aspire.Dashboard.Model.Otlp; using Microsoft.AspNetCore.Components; +using Microsoft.FluentUI.AspNetCore.Components; +using Microsoft.JSInterop; namespace Aspire.Dashboard.Components.Dialogs; -public partial class TextVisualizerDialog : ComponentBase +public partial class TextVisualizerDialog : ComponentBase, IAsyncDisposable { private const string XmlFormat = "xml"; private const string JsonFormat = "json"; - private const string PlaintextFormat = "text"; + private const string PlaintextFormat = "plaintext"; private static readonly JsonSerializerOptions s_serializerOptions = new() { WriteIndented = true }; private List> _options = null!; private readonly HashSet _enabledOptions = []; - private string _selectedOption = null!; private string _formattedText = string.Empty; + private string? _formatKind; + private readonly string _copyButtonId = $"copy-{Guid.NewGuid():N}"; private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; - private bool _isSelectFormatPopupOpen; + private IJSObjectReference? _jsModule; + + [Inject] + public required IJSRuntime JS { get; init; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + _jsModule = await JS.InvokeAsync("import", "/Components/Dialogs/TextVisualizerDialog.razor.js"); + } + + if (_jsModule is not null && _formatKind is not null) + { + await _jsModule.InvokeVoidAsync("connectObserver"); + } + } protected override void OnParametersSet() { @@ -39,30 +57,33 @@ protected override void OnParametersSet() if (TryFormatJson()) { - _selectedOption = JsonFormat; _enabledOptions.Add(JsonFormat); } else if (TryFormatXml()) { - _selectedOption = XmlFormat; _enabledOptions.Add(XmlFormat); } else { - _selectedOption = PlaintextFormat; _formattedText = Content.Text; + _formatKind = null; } } - private ICollection GetLines() + private string GetLogContentClass() { - var lines = Regex.Split(_formattedText, "(\r\n|\n)", RegexOptions.Compiled).ToList(); + return $"log-content highlight-line language-{_formatKind}"; + } + + private ICollection GetLines() + { + var lines = Regex.Split(_formattedText, Environment.NewLine, RegexOptions.Compiled).ToList(); if (lines.Count > 0 && lines[0].Length == 0) { lines.RemoveAt(0); } - return lines.Select((line, index) => new ResourceLogLine(index, line, false)).ToList(); + return lines.Select((line, index) => new StringLogLine(index, line, _formatKind is not null)).ToList(); } private bool TryFormatXml() @@ -70,12 +91,11 @@ private bool TryFormatXml() try { _formattedText = XDocument.Parse(Content.Text).ToString(); + _formatKind = XmlFormat; return true; } catch (XmlException) { - // If the XML is invalid, just show the original text - _formattedText = Content.Text; return false; } } @@ -89,37 +109,55 @@ private bool TryFormatJson() new JsonDocumentOptions { AllowTrailingCommas = true, + /* comments are not allowed in JSON, the only options are Skip or Disallow. Skip to allow showing formatted JSON in any case */ CommentHandling = JsonCommentHandling.Skip } ); _formattedText = JsonSerializer.Serialize(doc.RootElement, s_serializerOptions); + _formatKind = JsonFormat; return true; } catch (JsonException) { - // If the JSON is invalid, just show the original text - _formattedText = Content.Text; return false; } } - private void OnFormatOptionChanged() + private void OnFormatOptionChanged(MenuChangeEventArgs args) { - if (_selectedOption == XmlFormat) + if (args.Id == XmlFormat) { TryFormatXml(); } - else if (_selectedOption == JsonFormat) + else if (args.Id == JsonFormat) { TryFormatJson(); } else { _formattedText = Content.Text; + _formatKind = null; } + } - _isSelectFormatPopupOpen = false; + public async ValueTask DisposeAsync() + { + if (_jsModule != null) + { + try + { + await _jsModule.InvokeVoidAsync("disconnectObserver"); + await _jsModule.DisposeAsync(); + } + catch (JSDisconnectedException) + { + // Per https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-7.0#javascript-interop-calls-without-a-circuit + // this is one of the calls that will fail if the circuit is disconnected, and we just need to catch the exception so it doesn't pollute the logs + } + } } + + private record StringLogLine(int LineNumber, string Content, bool IsFormatted); } diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css index c413bc31d02..4c112cdd531 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css @@ -1,3 +1,14 @@ ::deep .text-visualizer-line-number { user-select: none; } + +::deep .text-visualizer-copy-button { + position: absolute; + right: calc(var(--design-unit) * 4px); + bottom: calc(var(--design-unit) * 4px); +} + +::deep .highlight-line { + width: 100%; + background: transparent; +} diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.js b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.js new file mode 100644 index 00000000000..d2b14e3760d --- /dev/null +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.js @@ -0,0 +1,30 @@ +let highlightObserver= new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.addedNodes.length === 0) { + return; + } + + for (let i = 0; i < mutation.addedNodes.length; i++) { + let node = mutation.addedNodes[i] + if (node.classList && node.classList.contains("highlight-line")) { + hljs.highlightElement(node); + } + } + }) +}) + +export function connectObserver() { + highlightObserver.observe(document.getElementById("test"), { + childList: true, + subtree: true + }) + + const existingElementsToHighlight = document.getElementsByClassName("highlight-line"); + for (let i = 0; i < existingElementsToHighlight.length; i++) { + hljs.highlightElement(existingElementsToHighlight[i]); + } +} + +export function disconnectObserver() { + highlightObserver.disconnect() +} diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index 2b13072bf68..6fbb345085f 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -258,8 +258,8 @@ public async Task OpenTextVisualizerAsync(string value, string valueDescription) var parameters = new DialogParameters { Title = valueDescription, - Width = ViewportInformation.IsDesktop ? "60vw" : "100vw", - Height = ViewportInformation.IsDesktop ? "60vh" : "100vh", + Width = ViewportInformation.IsDesktop ? "75vw" : "100vw", + Height = ViewportInformation.IsDesktop ? "75vh" : "100vh", TrapFocus = true, Modal = true, PreventScroll = true, diff --git a/src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-default.min.css b/src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-default.min.css new file mode 100644 index 00000000000..a75ea911626 --- /dev/null +++ b/src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-default.min.css @@ -0,0 +1,9 @@ +/*! + Theme: Default + Description: Original highlight.js style + Author: (c) Ivan Sagalaev + Maintainer: @highlightjs/core-team + Website: https://highlightjs.org/ + License: see project LICENSE + Touched: 2021 +*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} \ No newline at end of file diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index c8696b5f8e3..efe4711defd 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -17,7 +17,7 @@ if (firstUndefinedElement) { // Register a global click event listener to handle copy button clicks. // Required because an "onclick" attribute is denied by CSP. document.addEventListener("click", function (e) { - if (e.target.tagName.toLowerCase() === "fluent-menu-item" && e.target.getAttribute("data-copybutton")) { + if ((e.target.tagName.toLowerCase() === "fluent-menu-item" || e.target.tagName.toLowerCase() === "fluent-button") && e.target.getAttribute("data-copybutton")) { buttonCopyTextToClipboard(e.target); e.stopPropagation(); } diff --git a/src/Aspire.Dashboard/wwwroot/js/highlight-11.10.0.min.js b/src/Aspire.Dashboard/wwwroot/js/highlight-11.10.0.min.js new file mode 100644 index 00000000000..5442f21b949 --- /dev/null +++ b/src/Aspire.Dashboard/wwwroot/js/highlight-11.10.0.min.js @@ -0,0 +1,1232 @@ +/*! + Highlight.js v11.10.0 (git: 366a8bd012) + (c) 2006-2024 Josh Goebel and other contributors + License: BSD-3-Clause + */ +var hljs=function(){"use strict";function e(n){ +return n instanceof Map?n.clear=n.delete=n.set=()=>{ +throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ +throw Error("set is read-only") +}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ +const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) +})),n}class n{constructor(e){ +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} +ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ +return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") +}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] +;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope +;class r{constructor(e,n){ +this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ +this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ +if(e.startsWith("language:"))return e.replace("language:","language-") +;if(e.includes(".")){const t=e.split(".") +;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") +}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} +closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ +this.buffer+=``}}const s=(e={})=>{const n={children:[]} +;return Object.assign(n,e),n};class o{constructor(){ +this.rootNode=s(),this.stack=[this.rootNode]}get top(){ +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ +this.top.children.push(e)}openNode(e){const n=s({scope:e}) +;this.add(n),this.stack.push(n)}closeNode(){ +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ +return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), +n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ +o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} +addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ +this.closeNode()}__addSublanguage(e,n){const t=e.root +;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ +return new r(this,this.options).value()}finalize(){ +return this.closeAllNodes(),!0}}function c(e){ +return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} +function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} +function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ +const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} +function p(e){return RegExp(e.toString()+"|").exec("").length-1} +const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ +;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t +;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} +i+=a.substring(0,e.index), +a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], +"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} +const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",w="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",N="\\b(0b[01]+)",v={ +begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'", +illegal:"\\n",contains:[v]},x={scope:"string",begin:'"',end:'"',illegal:"\\n", +contains:[v]},O=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, +contains:[]},t);i.contains.push({scope:"doctag", +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) +;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) +;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i +},M=O("//","$"),A=O("/\\*","\\*/"),S=O("#","$");var C=Object.freeze({ +__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ +scope:"number",begin:N,relevance:0},BINARY_NUMBER_RE:N,COMMENT:O, +C_BLOCK_COMMENT_MODE:A,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", +begin:w,relevance:0},C_NUMBER_RE:w,END_SAME_AS_BEGIN:e=>Object.assign(e,{ +"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:S,IDENT_RE:f, +MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, +NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, +PHRASAL_WORDS_MODE:{ +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ +},QUOTE_STRING_MODE:x,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, +end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", +SHEBANG:(e={})=>{const n=/^#![ ]*\// +;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, +end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, +TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, +UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ +"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ +void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ +n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", +e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, +void 0===e.relevance&&(e.relevance=0))}function I(e,n){ +Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ +if(e.match){ +if(e.begin||e.end)throw Error("begin & end are not supported with match") +;e.begin=e.match,delete e.match}}function B(e,n){ +void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return +;if(e.starts)throw Error("beforeMatch cannot be used with starts") +;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] +})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ +relevance:0,contains:[Object.assign(t,{endsParent:!0})] +},e.relevance=0,delete t.beforeMatch +},F=["of","and","for","in","not","or","if","then","parent","list","value"],z="keyword" +;function j(e,n,t=z){const a=Object.create(null) +;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ +Object.assign(a,j(e[t],n,t))})),a;function i(e,t){ +n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") +;a[t[0]]=[e,U(t[0],t[1])]}))}}function U(e,n){ +return n?Number(n):(e=>F.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ +console.error(e)},q=(e,...n)=>{console.log("WARN: "+e,...n)},H=(e,n)=>{ +P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) +},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} +;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) +;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope +}),(e=>{if(Array.isArray(e.begin)){ +if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), +G +;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), +G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ +if(Array.isArray(e.end)){ +if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), +G +;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), +G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ +function n(n,t){ +return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) +}class t{constructor(){ +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} +addRule(e,n){ +n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), +this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) +;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex +;const n=this.matcherRe.exec(e);if(!n)return null +;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] +;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ +this.rules=[],this.multiRegexes=[], +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ +if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t +;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), +n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ +this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ +const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex +;let t=n.exec(e) +;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ +const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} +return t&&(this.regexIndex+=t.position+1, +this.regexIndex===this.count&&this.considerAll()),t}} +if(e.compilerExtensions||(e.compilerExtensions=[]), +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") +;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r +;if(r.isCompiled)return o +;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), +r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), +l=r.keywords.$pattern, +delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=j(r.keywords,e.case_insensitive)), +o.keywordPatternRe=n(l,!0), +s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), +r.end&&(o.endRe=n(o.end)), +o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), +r.illegal&&(o.illegalRe=n(r.illegal)), +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ +variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ +starts:e.starts?a(e.starts):null +}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) +})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i +;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" +}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" +}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ +return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ +constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} +const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ +const a=Object.create(null),i=Object.create(null),r=[];let s=!0 +;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ +disableAutodetect:!0,name:"Plain text",contains:[]};let p={ +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", +cssSelector:"pre code",languages:null,__emitter:l};function _(e){ +return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" +;"object"==typeof n?(a=e, +t=n.ignoreIllegals,i=n.language):(H("10.7.0","highlight(lang, code, ...args) has been deprecated."), +H("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), +i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};O("before:highlight",r) +;const s=r.result?r.result:f(r.language,r.code,t) +;return s.code=r.code,O("after:highlight",s),s}function f(e,t,i,r){ +const l=Object.create(null);function c(){if(!O.keywords)return void A.addText(S) +;let e=0;O.keywordPatternRe.lastIndex=0;let n=O.keywordPatternRe.exec(S),t="" +;for(;n;){t+=S.substring(e,n.index) +;const i=N.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,O.keywords[a]);if(r){ +const[e,a]=r +;if(A.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ +const t=N.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] +;e=O.keywordPatternRe.lastIndex,n=O.keywordPatternRe.exec(S)}var a +;t+=S.substring(e),A.addText(t)}function d(){null!=O.subLanguage?(()=>{ +if(""===S)return;let e=null;if("string"==typeof O.subLanguage){ +if(!a[O.subLanguage])return void A.addText(S) +;e=f(O.subLanguage,S,!0,M[O.subLanguage]),M[O.subLanguage]=e._top +}else e=E(S,O.subLanguage.length?O.subLanguage:null) +;O.relevance>0&&(C+=e.relevance),A.__addSublanguage(e._emitter,e.language) +})():c(),S=""}function g(e,n){ +""!==e&&(A.startScope(n),A.addText(e),A.endScope())}function u(e,n){let t=1 +;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} +const a=N.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(S=i,c(),S=""),t++}} +function b(e,n){ +return e.scope&&"string"==typeof e.scope&&A.openNode(N.classNameAliases[e.scope]||e.scope), +e.beginScope&&(e.beginScope._wrap?(g(S,N.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), +S=""):e.beginScope._multi&&(u(e.beginScope,n),S="")),O=Object.create(e,{parent:{ +value:O}}),O}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) +;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) +;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ +for(;e.endsParent&&e.parent;)e=e.parent;return e}} +if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ +return 0===O.matcher.regexIndex?(S+=e[0],1):(D=!0,0)}function h(e){ +const n=e[0],a=t.substring(e.index),i=m(O,e,a);if(!i)return ee;const r=O +;O.endScope&&O.endScope._wrap?(d(), +g(n,O.endScope._wrap)):O.endScope&&O.endScope._multi?(d(), +u(O.endScope,e)):r.skip?S+=n:(r.returnEnd||r.excludeEnd||(S+=n), +d(),r.excludeEnd&&(S=n));do{ +O.scope&&A.closeNode(),O.skip||O.subLanguage||(C+=O.relevance),O=O.parent +}while(O!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} +let y={};function w(a,r){const o=r&&r[0];if(S+=a,null==o)return d(),0 +;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ +if(S+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) +;throw n.languageName=e,n.badRule=y.rule,n}return 1} +if(y=r,"begin"===r.type)return(e=>{ +const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] +;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) +;return a.skip?S+=t:(a.excludeBegin&&(S+=t), +d(),a.returnBegin||a.excludeBegin||(S=t)),b(a,e),a.returnBegin?0:t.length})(r) +;if("illegal"===r.type&&!i){ +const e=Error('Illegal lexeme "'+o+'" for mode "'+(O.scope||"")+'"') +;throw e.mode=O,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} +if("illegal"===r.type&&""===o)return 1 +;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") +;return S+=o,o.length}const N=v(e) +;if(!N)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') +;const k=Q(N);let x="",O=r||k;const M={},A=new p.__emitter(p);(()=>{const e=[] +;for(let n=O;n!==N;n=n.parent)n.scope&&e.unshift(n.scope) +;e.forEach((e=>A.openNode(e)))})();let S="",C=0,T=0,R=0,D=!1;try{ +if(N.__emitTokens)N.__emitTokens(t,A);else{for(O.matcher.considerAll();;){ +R++,D?D=!1:O.matcher.considerAll(),O.matcher.lastIndex=T +;const e=O.matcher.exec(t);if(!e)break;const n=w(t.substring(T,e.index),e) +;T=e.index+n}w(t.substring(T))}return A.finalize(),x=A.toHTML(),{language:e, +value:x,relevance:C,illegal:!1,_emitter:A,_top:O}}catch(n){ +if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), +illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, +context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:x},_emitter:A};if(s)return{ +language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:A,_top:O} +;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ +const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} +;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(x).map((n=>f(n,e,!1))) +;i.unshift(t);const r=i.sort(((e,n)=>{ +if(e.relevance!==n.relevance)return n.relevance-e.relevance +;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 +;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s +;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ +let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" +;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) +;return n||(q(o.replace("{}",t[1])), +q("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} +return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return +;if(O("before:highlightElement",{el:e,language:t +}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) +;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), +console.warn("The element with unescaped HTML:"), +console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) +;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) +;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t +;e.classList.add("hljs"),e.classList.add("language-"+a) +})(e,t,r.language),e.result={language:r.language,re:r.relevance, +relevance:r.relevance},r.secondBest&&(e.secondBest={ +language:r.secondBest.language,relevance:r.secondBest.relevance +}),O("after:highlightElement",{el:e,result:r,text:a})}let w=!1;function N(){ +"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):w=!0 +}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} +function k(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ +i[e.toLowerCase()]=n}))}function x(e){const n=v(e) +;return n&&!n.disableAutodetect}function O(e,n){const t=e;r.forEach((e=>{ +e[t]&&e[t](n)}))} +"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ +w&&N()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:N, +highlightElement:y, +highlightBlock:e=>(H("10.7.0","highlightBlock will be removed entirely in v12.0"), +H("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, +initHighlighting:()=>{ +N(),H("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, +initHighlightingOnLoad:()=>{ +N(),H("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") +},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ +if(K("Language definition for '{}' could not be registered.".replace("{}",e)), +!s)throw n;K(n),i=c} +i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&k(i.aliases,{ +languageName:e})},unregisterLanguage:e=>{delete a[e] +;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, +listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:k, +autoDetection:x,inherit:Y,addPlugin:e=>{(e=>{ +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ +e["before:highlightBlock"](Object.assign({block:n.el},n)) +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ +e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, +removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ +s=!1},t.safeMode=()=>{s=!0},t.versionString="11.10.0",t.regex={concat:b, +lookahead:d,either:m,optional:u,anyNumberOfTimes:g} +;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t +},te=ne({});te.newInstance=()=>ne({});const ae=e=>({IMPORTANT:{scope:"meta", +begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ +scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, +FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, +ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", +contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ +scope:"number", +begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", +relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/} +}),ie=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","optgroup","option","p","picture","q","quote","samp","section","select","source","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video","defs","g","marker","mask","pattern","svg","switch","symbol","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feGaussianBlur","feImage","feMerge","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","linearGradient","radialGradient","stop","circle","ellipse","image","line","path","polygon","polyline","rect","text","use","textPath","tspan","foreignObject","clipPath"],re=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"].sort().reverse(),se=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"].sort().reverse(),oe=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"].sort().reverse(),le=["accent-color","align-content","align-items","align-self","alignment-baseline","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-end-end-radius","border-end-start-radius","border-right-color","border-right-style","border-right-width","border-spacing","border-start-end-radius","border-start-start-radius","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","cx","cy","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","color-scheme","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","empty-cells","enable-background","fill","fill-opacity","fill-rule","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","flood-color","flood-opacity","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-horizontal","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","inset","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","kerning","justify-content","justify-items","justify-self","left","letter-spacing","lighting-color","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","marker","marker-end","marker-mid","marker-start","mask","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","r","resize","rest","rest-after","rest-before","right","rotate","row-gap","scale","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","shape-rendering","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","speak","speak-as","src","tab-size","table-layout","text-anchor","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip-ink","text-decoration-style","text-decoration-thickness","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-offset","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","vector-effect","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","x","y","z-index"].sort().reverse(),ce=se.concat(oe).sort().reverse() +;var de="[0-9](_*[0-9])*",ge=`\\.(${de})`,ue="[0-9a-fA-F](_*[0-9a-fA-F])*",be={ +className:"number",variants:[{ +begin:`(\\b(${de})((${ge})|\\.)?|(${ge}))[eE][+-]?(${de})[fFdD]?\\b`},{ +begin:`\\b(${de})((${ge})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${ge})[fFdD]?\\b`},{begin:`\\b(${de})[fFdD]\\b`},{ +begin:`\\b0[xX]((${ue})\\.?|(${ue})?\\.(${ue}))[pP][+-]?(${de})[fFdD]?\\b`},{ +begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${ue})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};function me(e,n,t){return-1===t?"":e.replace(n,(a=>me(e,n,t-1)))} +const pe="[A-Za-z$_][0-9A-Za-z$_]*",_e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],he=["true","false","null","undefined","NaN","Infinity"],fe=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],Ee=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],ye=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],Ne=[].concat(ye,fe,Ee) +;function ve(e){const n=e.regex,t=pe,a={begin:/<[A-Za-z0-9\\._:-]+/, +end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ +const t=e[0].length+e.index,a=e.input[t] +;if("<"===a||","===a)return void n.ignoreMatch();let i +;">"===a&&(((e,{after:n})=>{const t="e+"\\s*\\(")), +n.concat("(?!",v.join("|"),")")),t,n.lookahead(/\s*\(/)), +className:"title.function",relevance:0};var v;const k={ +begin:n.concat(/\./,n.lookahead(n.concat(t,/(?![0-9A-Za-z$_(])/))),end:t, +excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},x={ +match:[/get|set/,/\s+/,t,/(?=\()/],className:{1:"keyword",3:"title.function"}, +contains:[{begin:/\(\)/},f] +},O="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",M={ +match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(O)], +keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} +;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ +PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, +contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ +label:"use_strict",className:"meta",relevance:10, +begin:/^\s*['"]use (strict|asm)['"]/ +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ +className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ +begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", +keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ +className:"function",begin:O,returnBegin:!0,end:"\\s*=>",contains:[{ +className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ +className:null,begin:/\(\s*\)/,skip:!0},{begin:/(\s*)\(/,end:/\)/, +excludeBegin:!0,excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0 +},{match:/\s+/,relevance:0},{variants:[{begin:"<>",end:""},{ +match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, +"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ +begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},w,{ +beginKeywords:"while if switch catch for"},{ +begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", +returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, +className:"title.function"})]},{match:/\.\.\./,relevance:0},k,{match:"\\$"+t, +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, +contains:[f]},N,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},E,x,{match:/\$[(.]/}]}} +const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Oe=["init","self"].map(ke),Me=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","package","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Se=["false","nil","true"],Ce=["assignment","associativity","higherThan","left","lowerThan","none","right"],Te=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],Re=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],De=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Ie=m(De,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Le=b(De,Ie,"*"),Be=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),$e=m(Be,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b(Be,$e,"*"),ze=b(/[A-Z]/,$e,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Ue=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] +;var Pe=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ +begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} +;Object.assign(t,{className:"variable",variants:[{ +begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ +className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE] +},r=e.inherit(e.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),s={ +begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, +end:/(\w+)/,className:"string"})]}},o={className:"string",begin:/"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(o);const l={begin:/\$?\(\(/, +end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] +},c=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 +}),d={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, +contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ +name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, +keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], +literal:["true","false"], +built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] +},contains:[c,e.SHEBANG(),d,l,r,s,{match:/(\/[a-z._-]+)+/},o,{match:/\\"/},{ +className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}},grmr_c:e=>{ +const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ +match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef elifdef elifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","typeof","typeof_unqual","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], +type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_BitInt","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal96","_Decimal128","_Decimal64x","_Decimal128x","_Float16","_Float32","_Float64","_Float128","_Float32x","_Float64x","_Float128x","const","static","constexpr","complex","bool","imaginary"], +literal:"true false NULL", +built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" +},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], +relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, +keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, +end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] +}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, +disableAutodetect:!0,illegal:"=]/,contains:[{ +beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, +strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ +contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{ +begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)" +},{ +begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], +keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], +literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], +_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] +},b={className:"function.dispatch",relevance:0,keywords:{ +_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] +}, +begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) +},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ +begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ +className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, +contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, +relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] +},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", +aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ +match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], +className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ +keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), +built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], +literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ +begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ +begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] +},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, +keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, +end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ +},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ +begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, +contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) +;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], +o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ +illegal:/\n/})];const g={variants:[{className:"string", +begin:/"""("*)(?!")(.|\n)*?"""\1/,relevance:1 +},c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},u={begin:"<",end:">", +contains:[{beginKeywords:"in out"},t] +},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ +begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], +keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, +contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ +begin:"\x3c!--|--\x3e"},{begin:""}]}] +}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", +end:"$",keywords:{ +keyword:"if else elif endif define undef warning error line region endregion pragma checksum" +}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, +illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" +},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", +relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", +begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ +className:"string",begin:/"/,end:/"/}]},{ +beginKeywords:"new return throw await else",relevance:0},{className:"function", +begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ +beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", +relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", +begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, +contains:[g,a,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ +const n=e.regex,t=ae(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ +name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ +keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, +contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ +},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 +},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 +},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ +begin:":("+se.join("|")+")"},{begin:":(:)?("+oe.join("|")+")"}] +},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+le.join("|")+")\\b"},{ +begin:/:/,end:/[;}{]/, +contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ +begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" +},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, +excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", +relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ +},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ +$pattern:/[a-z-]+/,keyword:"and or not only",attribute:re.join(" ")},contains:[{ +begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ +className:"selector-tag",begin:"\\b("+ie.join("|")+")\\b"}]}},grmr_diff:e=>{ +const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ +className:"meta",relevance:10, +match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) +},{className:"comment",variants:[{ +begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), +end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ +className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, +end:/$/}]}},grmr_go:e=>{const n={ +keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], +type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], +literal:["true","false","iota","nil"], +built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] +};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex +;return{name:"GraphQL",aliases:["gql"],case_insensitive:!0,disableAutodetect:!1, +keywords:{ +keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], +literal:["true","false","null"]}, +contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ +scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", +begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, +end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ +scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), +relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ +className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ +begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, +end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ +begin:/\$\{(.*?)\}/}]},r={className:"literal", +begin:/\bon|off|true|false|yes|no\b/},s={className:"string", +contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ +begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] +},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 +},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ +name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, +contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ +begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), +className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ +const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+me("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits","goto"], +literal:["false","true","null"], +type:["char","boolean","long","float","int","byte","short","double"], +built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ +begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, +className:"string",contains:[e.BACKSLASH_ESCAPE] +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ +1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ +begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", +3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"new throw return else",relevance:0},{ +begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0, +contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,be,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},be,r]}},grmr_javascript:ve, +grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", +beginKeywords:n.join(" ")};return{name:"JSON",aliases:["jsonc"],keywords:{ +literal:n},contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/, +relevance:1.01},{match:/[{}[\],:]/,className:"punctuation",relevance:0 +},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], +illegal:"\\S"}},grmr_kotlin:e=>{const n={ +keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", +built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", +literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" +},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ +className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", +variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", +illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, +contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ +className:"meta", +begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" +},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, +end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] +},l=be,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ +variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, +contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], +{name:"Kotlin",aliases:["kt","kts"],keywords:n, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", +begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", +begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", +begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", +returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ +begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, +contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, +keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, +endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, +endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 +},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ +begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ +3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, +illegal:"extends implements",contains:[{ +beginKeywords:"public protected internal private constructor" +},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, +excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, +excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", +end:"$",illegal:"\n"},l]}},grmr_less:e=>{ +const n=ae(e),t=ce,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ +className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, +relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", +attribute:re.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, +relevance:0} +;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ +begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", +excludeEnd:!0} +},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ +className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 +},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ +begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, +contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", +returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ +},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+le.join("|")+")\\b", +end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] +},m={className:"keyword", +begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", +starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ +className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a +}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ +begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, +returnEnd:!0,illegal:"[<='$\"]",relevance:0, +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ +begin:"\\b("+ie.join("|")+")\\b",className:"selector-tag" +},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ +className:"selector-pseudo",begin:":("+se.join("|")+")"},{ +className:"selector-pseudo",begin:":(:)?("+oe.join("|")+")"},{begin:/\(/, +end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ +begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} +;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), +{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, +grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] +},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 +})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, +literal:"true false nil", +keyword:"and break do else elseif end for goto if in local not or repeat return then until while", +built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" +},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", +contains:[e.inherit(e.TITLE_MODE,{ +begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", +begin:"\\(",endsWithParent:!0,contains:i}].concat(i) +},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", +begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ +className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ +const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ +variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ +begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, +relevance:2},{ +begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), +relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ +begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ +},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, +returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", +excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", +end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], +variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] +},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ +begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] +}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) +;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) +})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", +contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", +end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, +end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ +begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ +begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", +contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ +begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},{scope:"literal", +match:/&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/}]}}, +grmr_objectivec:e=>{const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, +keyword:["@interface","@class","@protocol","@implementation"]};return{ +name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], +keywords:{"variable.language":["this","super"],$pattern:n, +keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], +literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], +built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], +type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] +},illegal:"/,end:/$/,illegal:"\\n" +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", +begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, +contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, +relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ +$pattern:/[\w.]+/, +keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot class close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl field fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map method mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" +},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, +end:/\}/},s={scope:"attr",match:/\s+:\s*\w+(\s*\(.*?\))?/},o={scope:"variable", +variants:[{begin:/\$\d/},{ +begin:n.concat(/[$%@](?!")(\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") +},{begin:/[$%@](?!")[^\s\w{=]|\$=/,relevance:0}],contains:[s]},l={ +className:"number",variants:[{match:/0?\.[0-9][0-9_]+\b/},{ +match:/\bv?(0|[1-9][0-9_]*(\.[0-9_]+)?|[1-9][0-9_]*)\b/},{ +match:/\b0[0-7][0-7_]*\b/},{match:/\b0x[0-9a-fA-F][0-9a-fA-F_]*\b/},{ +match:/\b0b[0-1][0-1_]*\b/}],relevance:0 +},c=[e.BACKSLASH_ESCAPE,i,o],d=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],g=(e,a,i="\\1")=>{ +const r="\\1"===i?i:n.concat(i,a) +;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) +},u=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),b=[o,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ +endsWithParent:!0}),r,{className:"string",contains:c,variants:[{ +begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", +end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ +begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", +relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", +contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ +begin:"-?\\w+\\s*=>",relevance:0}]},l,{ +begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", +keywords:"split return print reverse grep",relevance:0, +contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ +begin:g("s|tr|y",n.either(...d,{capture:!0}))},{begin:g("s|tr|y","\\(","\\)")},{ +begin:g("s|tr|y","\\[","\\]")},{begin:g("s|tr|y","\\{","\\}")}],relevance:2},{ +className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ +begin:u("(?:m|qr)?",/\//,/\//)},{begin:u("m|qr",n.either(...d,{capture:!0 +}),/\1/)},{begin:u("m|qr",/\(/,/\)/)},{begin:u("m|qr",/\[/,/\]/)},{ +begin:u("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub method", +end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE,s] +},{className:"class",beginKeywords:"class",end:"[;{]",excludeEnd:!0,relevance:5, +contains:[e.TITLE_MODE,s,l]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$", +end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$", +className:"comment"}]}];return i.contains=b,r.contains=b,{name:"Perl", +aliases:["pl","pm"],keywords:a,contains:b}},grmr_php:e=>{ +const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ +scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ +begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null +}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ +illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ +begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, +contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ +n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ +begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ +begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ +begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ +begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" +}],relevance:0 +},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ +keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ +n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) +})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ +match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ +1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ +match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" +}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ +match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", +3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], +scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", +3:"variable.language"}}]},E={scope:"attr", +match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, +begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] +},w={relevance:0, +match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], +scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(w) +;const N=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, +keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, +endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ +begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, +contains:["self",...N]},...N,{scope:"meta",match:i}] +},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ +scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, +keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, +contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ +begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ +begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,w,f,{ +match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ +scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, +excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" +},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", +begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, +contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ +beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", +illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ +beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ +beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, +contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ +beginKeywords:"use",relevance:0,end:";",contains:[{ +match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} +},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ +begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", +end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 +},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, +skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, +contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", +aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ +const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ +$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, +built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], +literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], +type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] +},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, +end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ +className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, +end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, +relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ +begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, +end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, +contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ +className:"number",relevance:0,variants:[{ +begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ +begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ +begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` +},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` +}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, +contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ +className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, +end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, +contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ +name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, +illegal:/(<\/|\?)|=>/,contains:[r,u,{scope:"variable.language",match:/\bself\b/ +},{beginKeywords:"if",relevance:0},{match:/\bor\b/,scope:"keyword" +},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{1:"keyword", +3:"title.function"},contains:[m]},{variants:[{ +match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], +scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ +className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, +grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", +starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ +begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ +const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) +;return{name:"R",keywords:{$pattern:t, +keyword:"function if in break next repeat else for while", +literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", +built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" +},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, +starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), +endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ +scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 +}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] +}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], +variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', +relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ +1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, +match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ +2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, +match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ +match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", +contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ +const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ +"variable.constant":["__FILE__","__LINE__","__ENCODING__"], +"variable.language":["self","super"], +keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], +built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], +literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ +begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] +}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 +}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, +end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ +begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ +begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, +end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ +begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ +begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ +begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ +begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ +begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), +contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, +contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", +relevance:0,variants:[{ +begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ +begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" +},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ +begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ +className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, +keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ +match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", +4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ +2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ +1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ +match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ +begin:e.IDENT_RE+"::"},{className:"symbol", +begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", +begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", +begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ +className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, +relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", +keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], +illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ +begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", +end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) +;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} +},{className:"meta.prompt", +begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", +starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", +aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, +contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, +grmr_rust:e=>{ +const n=e.regex,t=/(r#)?/,a=n.concat(t,e.UNDERSCORE_IDENT_RE),i=n.concat(t,e.IDENT_RE),r={ +className:"title.function.invoke",relevance:0, +begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,i,n.lookahead(/\s*\(/)) +},s="([ui](8|16|32|64|128|size)|f(32|64))?",o=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],l=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] +;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:l, +keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","union","unsafe","unsized","use","virtual","where","while","yield"], +literal:["true","false","Some","None","Ok","Err"],built_in:o},illegal:""},r]}}, +grmr_scss:e=>{const n=ae(e),t=oe,a=se,i="@[a-z-]+",r={className:"variable", +begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", +case_insensitive:!0,illegal:"[=/|']", +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ +className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ +className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 +},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", +begin:"\\b("+ie.join("|")+")\\b",relevance:0},{className:"selector-pseudo", +begin:":("+a.join("|")+")"},{className:"selector-pseudo", +begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, +contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", +begin:"\\b("+le.join("|")+")\\b"},{ +begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" +},{begin:/:/,end:/[;}{]/,relevance:0, +contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] +},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ +begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, +keyword:"and or not only",attribute:re.join(" ")},contains:[{begin:i, +className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" +},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] +},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", +aliases:["console","shellsession"],contains:[{className:"meta.prompt", +begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, +subLanguage:"bash"}}]}),grmr_sql:e=>{ +const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ +begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} +;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ +$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t +;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) +})(l,{when:e=>e.length<3}),literal:a,type:i, +built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] +},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, +keyword:l.concat(s),literal:a,type:i}},{className:"type", +begin:n.either("double precision","large object","with timezone","without timezone") +},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", +variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, +contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ +className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, +relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 +},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ +match:[/\./,m(...xe,...Oe)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), +relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ +className:"keyword", +match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Me).map(ke),...Oe)}]},l={ +$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Te),literal:Se},c=[i,r,o],g=[{ +match:b(/\./,m(...Re)),relevance:0},{className:"built_in", +match:b(/\b/,m(...Re),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ +className:"operator",relevance:0,variants:[{match:Le},{match:`\\.(\\.|${Ie})+`}] +}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, +variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ +match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ +},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ +match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] +}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) +}),w=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ +}),N=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),w(e)] +}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),w(e)]}),k={ +className:"string", +variants:[N(),N("#"),N("##"),N("###"),v(),v("#"),v("##"),v("###")] +},x=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, +contains:[e.BACKSLASH_ESCAPE]}],O={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, +contains:x},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, +contains:[...x,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},A={ +scope:"regexp",variants:[M("###"),M("##"),M("#"),O]},S={match:b(/`/,Fe,/`/) +},C=[S,{className:"variable",match:/\$\d+/},{className:"variable", +match:`\\$${$e}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ +contains:[{begin:/\(/,end:/\)/,keywords:Ue,contains:[...p,f,k]}]}},{ +scope:"keyword",match:b(/@/,m(...je),d(m(/\(/,/\s+/)))},{scope:"meta", +match:b(/@/,Fe)}],R={match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", +match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,$e,"+") +},{className:"type",match:ze,relevance:0},{match:/[?!]+/,relevance:0},{ +match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(ze)),relevance:0}]},D={ +begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) +;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ +match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 +},...a,A,...c,...g,...p,f,k,...C,...T,R]},L={begin://, +keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, +contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, +relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", +match:Fe}]},...a,...c,...p,f,k,...T,R,I],endsParent:!0,illegal:/["']/},$={ +match:[/(func|macro)/,/\s+/,m(S.match,Fe,Le)],className:{1:"keyword", +3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},F={ +match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, +contains:[L,B,n],illegal:/\[|%/},z={match:[/operator/,/\s+/,Le],className:{ +1:"keyword",3:"title"}},j={begin:[/precedencegroup/,/\s+/,ze],className:{ +1:"keyword",3:"title"},contains:[R],keywords:[...Ce,...Se],end:/}/},U={ +begin:[/(struct|protocol|class|extension|enum|actor)/,/\s+/,Fe,/\s*/], +beginScope:{1:"keyword",3:"title.class"},keywords:l,contains:[L,...c,{begin:/:/, +end:/\{/,keywords:l,contains:[{scope:"title.class.inherited",match:ze},...c], +relevance:0}]};for(const e of k.variants){ +const n=e.contains.find((e=>"interpol"===e.label));n.keywords=l +;const t=[...c,...g,...p,f,k,...C];n.contains=[...t,{begin:/\(/,end:/\)/, +contains:["self",...t]}]}return{name:"Swift",keywords:l, +contains:[...a,$,F,U,z,j,{beginKeywords:"import",end:/$/,contains:[...a], +relevance:0},A,...c,...g,...p,f,k,...C,...T,R,I]}},grmr_typescript:e=>{ +const n=ve(e),t=pe,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ +begin:[/namespace/,/\s+/,e.IDENT_RE],beginScope:{1:"keyword",3:"title.class"} +},r={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{ +keyword:"interface extends",built_in:a},contains:[n.exports.CLASS_REFERENCE] +},s={$pattern:pe, +keyword:_e.concat(["type","interface","public","private","protected","implements","declare","abstract","readonly","enum","override","satisfies"]), +literal:he,built_in:Ne.concat(a),"variable.language":we},o={className:"meta", +begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) +;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} +;Object.assign(n.keywords,s),n.exports.PARAMS_CONTAINS.push(o) +;const c=n.contains.find((e=>"attr"===e.className)) +;return n.exports.PARAMS_CONTAINS.push([n.exports.CLASS_REFERENCE,c]), +n.contains=n.contains.concat([o,i,r]), +l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, +begin:/^\s*['"]use strict['"]/ +}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ +name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ +const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ +className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ +begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ +begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] +},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] +}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) +;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, +classNameAliases:{label:"symbol"},keywords:{ +keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", +built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", +type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", +literal:"true false nothing"}, +illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ +className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, +end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, +variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ +},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ +begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ +className:"label",begin:/^\w+:/},o,l,{className:"meta", +begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, +end:/$/,keywords:{ +keyword:"const disable else elseif enable end externalsource if region then"}, +contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) +;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, +keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] +},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], +className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ +match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ +begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", +3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, +className:"type"},{className:"keyword", +match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ +},{className:"number",relevance:0, +match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ +}]}},grmr_xml:e=>{ +const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] +},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ +className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ +endsWithParent:!0,illegal:/`]+/}]}]}]};return{ +name:"HTML, XML", +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], +case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ +className:"meta",begin://,contains:[i,r,o,s]}]}] +},e.COMMENT(//,{relevance:10}),{begin://, +relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, +relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ +className:"tag",begin:/<>|<\/>/},{className:"tag", +begin:n.concat(//,/>/,/\s/)))), +end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ +className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ +className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} +},grmr_yaml:e=>{ +const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ +className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", +variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ +end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, +end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", +contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ +begin:/\w[\w :()\./-]*:(?=[ \t]|$)/},{begin:/"\w[\w :()\./-]*":(?=[ \t]|$)/},{ +begin:/'\w[\w :()\./-]*':(?=[ \t]|$)/}]},{className:"meta",begin:"^---\\s*$", +relevance:10},{className:"string", +begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ +begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, +relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", +begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t +},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", +begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", +relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ +className:"number", +begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" +},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] +;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, +aliases:["yml"],contains:l}}});const Ke=te;for(const e of Object.keys(Pe)){ +const n=e.replace("grmr_","").replace("_","-");Ke.registerLanguage(n,Pe[e])} +return Ke}() +;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file From 7a6336e9e9fb68fd4f136e26d9fa4bbbfb739569 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 29 Jul 2024 19:11:02 -0400 Subject: [PATCH 09/25] stream data --- src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs | 6 +++++- src/Aspire.Dashboard/wwwroot/js/app.js | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index 6fbb345085f..4a45ea3100e 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -253,7 +253,7 @@ private void CloseMobileNavMenu() } [JSInvokable] - public async Task OpenTextVisualizerAsync(string value, string valueDescription) + public async Task OpenTextVisualizerAsync(IJSStreamReference valueStream, string valueDescription) { var parameters = new DialogParameters { @@ -265,6 +265,10 @@ public async Task OpenTextVisualizerAsync(string value, string valueDescription) PreventScroll = true, }; + await using var referenceStream = await valueStream.OpenReadStreamAsync(); + using var reader = new StreamReader(referenceStream); + var value = await reader.ReadToEndAsync(); + await DialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(value, valueDescription), parameters); } diff --git a/src/Aspire.Dashboard/wwwroot/js/app.js b/src/Aspire.Dashboard/wwwroot/js/app.js index efe4711defd..a4d4cc49112 100644 --- a/src/Aspire.Dashboard/wwwroot/js/app.js +++ b/src/Aspire.Dashboard/wwwroot/js/app.js @@ -307,7 +307,12 @@ window.registerOpenTextVisualizerOnClick = function(layout) { if (e.target.tagName.toLowerCase() === "fluent-menu-item" && text && description) { e.stopPropagation(); - layout.invokeMethodAsync("OpenTextVisualizerAsync", text, description); + + // data-text may be larger than the max Blazor message size limit for very large strings + // we have to stream it + const textAsArray = new TextEncoder().encode(text); + const textAsStream = DotNet.createJSStreamReference(textAsArray); + layout.invokeMethodAsync("OpenTextVisualizerAsync", textAsStream, description); } } From 3afba4c9b35831d007a9e858fb0cf5a7681ade7d Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 29 Jul 2024 20:14:31 -0400 Subject: [PATCH 10/25] Add TextVisualizerDialog component tests --- .../Dialogs/TextVisualizerDialog.razor | 2 +- .../Dialogs/TextVisualizerDialog.razor.cs | 57 ++++++------- .../Controls/TextVisualizerDialogTests.cs | 81 +++++++++++++++++++ 3 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 tests/Aspire.Dashboard.Components.Tests/Controls/TextVisualizerDialogTests.cs diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index f34462347c5..2f108ef138e 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -22,7 +22,7 @@ OnMenuChanged="@OnFormatOptionChanged"> @foreach (var option in _options) { - @option.Name + @option.Name }
diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 0e18edc0ad8..7048ed2a18e 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -14,19 +14,20 @@ namespace Aspire.Dashboard.Components.Dialogs; public partial class TextVisualizerDialog : ComponentBase, IAsyncDisposable { - private const string XmlFormat = "xml"; - private const string JsonFormat = "json"; - private const string PlaintextFormat = "plaintext"; + public const string XmlFormat = "xml"; + public const string JsonFormat = "json"; + public const string PlaintextFormat = "plaintext"; private static readonly JsonSerializerOptions s_serializerOptions = new() { WriteIndented = true }; - private List> _options = null!; - private readonly HashSet _enabledOptions = []; - private string _formattedText = string.Empty; - private string? _formatKind; private readonly string _copyButtonId = $"copy-{Guid.NewGuid():N}"; - private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; + private IJSObjectReference? _jsModule; + private List> _options = null!; + + public HashSet EnabledOptions { get; } = []; + public string FormattedText { get; private set; } = string.Empty; + public string FormatKind { get; private set; } = PlaintextFormat; [Inject] public required IJSRuntime JS { get; init; } @@ -38,7 +39,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) _jsModule = await JS.InvokeAsync("import", "/Components/Dialogs/TextVisualizerDialog.razor.js"); } - if (_jsModule is not null && _formatKind is not null) + if (_jsModule is not null && !string.Equals(FormatKind, PlaintextFormat, StringComparison.Ordinal)) { await _jsModule.InvokeVoidAsync("connectObserver"); } @@ -46,8 +47,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender) protected override void OnParametersSet() { - _enabledOptions.Clear(); - _enabledOptions.Add(PlaintextFormat); + EnabledOptions.Clear(); + EnabledOptions.Add(PlaintextFormat); _options = [ new SelectViewModel { Id = PlaintextFormat, Name = Loc[nameof(Resources.Dialogs.TextVisualizerDialogPlaintextFormat)] }, @@ -57,41 +58,41 @@ protected override void OnParametersSet() if (TryFormatJson()) { - _enabledOptions.Add(JsonFormat); + EnabledOptions.Add(JsonFormat); } else if (TryFormatXml()) { - _enabledOptions.Add(XmlFormat); + EnabledOptions.Add(XmlFormat); } else { - _formattedText = Content.Text; - _formatKind = null; + FormattedText = Content.Text; + FormatKind = PlaintextFormat; } } private string GetLogContentClass() { - return $"log-content highlight-line language-{_formatKind}"; + return $"log-content highlight-line language-{FormatKind}"; } private ICollection GetLines() { - var lines = Regex.Split(_formattedText, Environment.NewLine, RegexOptions.Compiled).ToList(); + var lines = Regex.Split(FormattedText, Environment.NewLine, RegexOptions.Compiled).ToList(); if (lines.Count > 0 && lines[0].Length == 0) { lines.RemoveAt(0); } - return lines.Select((line, index) => new StringLogLine(index, line, _formatKind is not null)).ToList(); + return lines.Select((line, index) => new StringLogLine(index, line, FormatKind is not null)).ToList(); } private bool TryFormatXml() { try { - _formattedText = XDocument.Parse(Content.Text).ToString(); - _formatKind = XmlFormat; + FormattedText = XDocument.Parse(Content.Text).ToString(); + FormatKind = XmlFormat; return true; } catch (XmlException) @@ -114,8 +115,8 @@ private bool TryFormatJson() } ); - _formattedText = JsonSerializer.Serialize(doc.RootElement, s_serializerOptions); - _formatKind = JsonFormat; + FormattedText = JsonSerializer.Serialize(doc.RootElement, s_serializerOptions); + FormatKind = JsonFormat; return true; } catch (JsonException) @@ -124,20 +125,22 @@ private bool TryFormatJson() } } - private void OnFormatOptionChanged(MenuChangeEventArgs args) + private void OnFormatOptionChanged(MenuChangeEventArgs args) => ChangeFormat(args.Id); + + public void ChangeFormat(string? newFormat) { - if (args.Id == XmlFormat) + if (newFormat == XmlFormat) { TryFormatXml(); } - else if (args.Id == JsonFormat) + else if (newFormat == JsonFormat) { TryFormatJson(); } else { - _formattedText = Content.Text; - _formatKind = null; + FormattedText = Content.Text; + FormatKind = PlaintextFormat; } } diff --git a/tests/Aspire.Dashboard.Components.Tests/Controls/TextVisualizerDialogTests.cs b/tests/Aspire.Dashboard.Components.Tests/Controls/TextVisualizerDialogTests.cs new file mode 100644 index 00000000000..2ba5a0bcf35 --- /dev/null +++ b/tests/Aspire.Dashboard.Components.Tests/Controls/TextVisualizerDialogTests.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using Aspire.Dashboard.Components.Dialogs; +using Aspire.Dashboard.Model; +using Bunit; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.FluentUI.AspNetCore.Components; +using Xunit; + +namespace Aspire.Dashboard.Components.Tests.Controls; + +public class TextVisualizerDialogTests : TestContext +{ + [Fact] + public async Task Render_TextVisualizerDialog_WithValidJson_FormatsJsonAsync() + { + var cut = SetUpDialog(out var dialogService); + await dialogService.ShowDialogAsync(new TextVisualizerDialogViewModel("""{"test": 4}""", string.Empty), []); + + var instance = cut.FindComponent().Instance; + + Assert.Equal(TextVisualizerDialog.JsonFormat, instance.FormatKind); + Assert.Equal([TextVisualizerDialog.JsonFormat, TextVisualizerDialog.PlaintextFormat], instance.EnabledOptions.ToImmutableSortedSet()); + } + + [Fact] + public async Task Render_TextVisualizerDialog_WithValidXml_FormatsXml_CanChangeFormatAsync() + { + const string rawXml = """text"""; + + var cut = SetUpDialog(out var dialogService); + await dialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(rawXml, string.Empty), []); + + var instance = cut.FindComponent().Instance; + + Assert.Equal(TextVisualizerDialog.XmlFormat, instance.FormatKind); + Assert.NotEqual(rawXml, instance.FormattedText); + Assert.Equal([TextVisualizerDialog.PlaintextFormat, TextVisualizerDialog.XmlFormat], instance.EnabledOptions.ToImmutableSortedSet()); + + // changing format works + instance.ChangeFormat(TextVisualizerDialog.PlaintextFormat); + + Assert.Equal(TextVisualizerDialog.PlaintextFormat, instance.FormatKind); + Assert.Equal(rawXml, instance.FormattedText); + } + + [Fact] + public async Task Render_TextVisualizerDialog_WithInvalidJson_FormatsPlaintextAsync() + { + const string rawText = """{{{{{{"test": 4}"""; + + var cut = SetUpDialog(out var dialogService); + await dialogService.ShowDialogAsync(new TextVisualizerDialogViewModel(rawText, string.Empty), []); + + var instance = cut.FindComponent().Instance; + + Assert.Equal(TextVisualizerDialog.PlaintextFormat, instance.FormatKind); + Assert.Equal(rawText, instance.FormattedText); + Assert.Equal([TextVisualizerDialog.PlaintextFormat], instance.EnabledOptions.ToImmutableSortedSet()); + } + + private IRenderedFragment SetUpDialog(out IDialogService dialogService) + { + Services.AddFluentUIComponents(); + Services.AddSingleton(); + Services.AddLocalization(); + var module = JSInterop.SetupModule("/Components/Dialogs/TextVisualizerDialog.razor.js"); + module.SetupVoid("connectObserver"); + + var cut = Render(builder => + { + builder.OpenComponent(0); + builder.CloseComponent(); + }); + + dialogService = Services.GetRequiredService(); + return cut; + } +} From 8cbdad8f44305ad127c0be8f298416d48df37e5c Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Mon, 29 Jul 2024 20:18:39 -0400 Subject: [PATCH 11/25] fix logical error --- .../Components/Dialogs/TextVisualizerDialog.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 7048ed2a18e..66d94b99289 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -39,7 +39,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) _jsModule = await JS.InvokeAsync("import", "/Components/Dialogs/TextVisualizerDialog.razor.js"); } - if (_jsModule is not null && !string.Equals(FormatKind, PlaintextFormat, StringComparison.Ordinal)) + if (_jsModule is not null && FormatKind != PlaintextFormat) { await _jsModule.InvokeVoidAsync("connectObserver"); } @@ -84,7 +84,7 @@ private ICollection GetLines() lines.RemoveAt(0); } - return lines.Select((line, index) => new StringLogLine(index, line, FormatKind is not null)).ToList(); + return lines.Select((line, index) => new StringLogLine(index, line, FormatKind != PlaintextFormat)).ToList(); } private bool TryFormatXml() From 1c618f2e57e76fb22a34c8520066fb22c4dae7e3 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Tue, 30 Jul 2024 12:14:20 -0400 Subject: [PATCH 12/25] fix console log css --- src/Aspire.Dashboard/Components/Controls/LogViewer.razor | 3 --- src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css | 5 ----- src/Aspire.Dashboard/wwwroot/css/app.css | 4 ++++ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor index 5a8fa26dadf..de275369d9d 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor @@ -1,8 +1,5 @@ @namespace Aspire.Dashboard.Components -@using System.Text -@using Aspire.Dashboard.ConsoleLogs @using Aspire.Dashboard.Model -@using System.Collections.Concurrent @inject IJSRuntime JS @implements IAsyncDisposable diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css index d8ca91d3251..83c9c14f20a 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css @@ -1,11 +1,6 @@ -::deep .console-overflow { - background-color: var(--console-background-color); -} - ::deep .console-container { background: var(--console-background-color); color: var(--console-font-color); - height: 100%; } ::deep .console-line-row:hover { diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index f76922b438f..6c6d7dd8e91 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -528,6 +528,10 @@ fluent-data-grid-cell.no-ellipsis { overflow: auto; } +.console-overflow { + background-color: var(--console-background-color); +} + .log-container { font-family: 'Cascadia Mono', Consolas, monospace; font-size: 13px; From fd2dc694a3d073593b539330cb5bbdd37b0afdb2 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 31 Jul 2024 08:42:21 +0800 Subject: [PATCH 13/25] Don't loose comments when formatting JSON --- .../Dialogs/TextVisualizerDialog.razor.cs | 90 ++++++++++++++++--- 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 66d94b99289..6d6730fcb70 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -1,6 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using System.Xml; @@ -17,7 +18,6 @@ public partial class TextVisualizerDialog : ComponentBase, IAsyncDisposable public const string XmlFormat = "xml"; public const string JsonFormat = "json"; public const string PlaintextFormat = "plaintext"; - private static readonly JsonSerializerOptions s_serializerOptions = new() { WriteIndented = true }; private readonly string _copyButtonId = $"copy-{Guid.NewGuid():N}"; private readonly string _openSelectFormatButtonId = $"select-format-{Guid.NewGuid():N}"; @@ -105,17 +105,9 @@ private bool TryFormatJson() { try { - using var doc = JsonDocument.Parse( - Content.Text, - new JsonDocumentOptions - { - AllowTrailingCommas = true, - /* comments are not allowed in JSON, the only options are Skip or Disallow. Skip to allow showing formatted JSON in any case */ - CommentHandling = JsonCommentHandling.Skip - } - ); - - FormattedText = JsonSerializer.Serialize(doc.RootElement, s_serializerOptions); + var formattedJson = FormatJson(Content.Text); + + FormattedText = formattedJson; FormatKind = JsonFormat; return true; } @@ -144,6 +136,78 @@ public void ChangeFormat(string? newFormat) } } + public static string FormatJson(string jsonString) + { + var jsonData = Encoding.UTF8.GetBytes(jsonString); + + // Initialize the Utf8JsonReader + var reader = new Utf8JsonReader(jsonData, new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Allow, + // Increase the allowed limit to 1000. This matches the allowed limit of the writer. + // It's ok to allow recursion here because JSON is read in a flat loop. There isn't a danger + // of recursive method calls that cause a stack overflow. + MaxDepth = 1000 + }); + + // Use a MemoryStream and Utf8JsonWriter to write the formatted JSON + using var stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.StartObject: + writer.WriteStartObject(); + break; + case JsonTokenType.EndObject: + writer.WriteEndObject(); + break; + case JsonTokenType.StartArray: + writer.WriteStartArray(); + break; + case JsonTokenType.EndArray: + writer.WriteEndArray(); + break; + case JsonTokenType.PropertyName: + writer.WritePropertyName(reader.GetString()!); + break; + case JsonTokenType.String: + writer.WriteStringValue(reader.GetString()); + break; + case JsonTokenType.Number: + if (reader.TryGetInt32(out var intValue)) + { + writer.WriteNumberValue(intValue); + } + else if (reader.TryGetDouble(out var doubleValue)) + { + writer.WriteNumberValue(doubleValue); + } + break; + case JsonTokenType.True: + writer.WriteBooleanValue(true); + break; + case JsonTokenType.False: + writer.WriteBooleanValue(false); + break; + case JsonTokenType.Null: + writer.WriteNullValue(); + break; + case JsonTokenType.Comment: + writer.WriteCommentValue(reader.GetComment()); + break; + } + } + + writer.Flush(); + var formattedJson = Encoding.UTF8.GetString(stream.ToArray()); + + return formattedJson; + } + public async ValueTask DisposeAsync() { if (_jsModule != null) From 1b8d8be56c417b5c8d4464b5a8ee9fead5db30c2 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Wed, 31 Jul 2024 12:09:37 -0400 Subject: [PATCH 14/25] run custom tool after merge --- .../Resources/Dialogs.Designer.cs | 314 ++++++------------ 1 file changed, 108 insertions(+), 206 deletions(-) diff --git a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs index 934f48a4c05..21102a3bdb1 100644 --- a/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs +++ b/src/Aspire.Dashboard/Resources/Dialogs.Designer.cs @@ -11,46 +11,32 @@ namespace Aspire.Dashboard.Resources { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Dialogs { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Dialogs() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aspire.Dashboard.Resources.Dialogs", typeof(Dialogs).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Aspire.Dashboard.Resources.Dialogs", typeof(Dialogs).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,345 +45,261 @@ internal Dialogs() { } } - /// - /// Looks up a localized string similar to Close. - /// - public static string ExemplarsDialogCloseButtonText { - get { - return ResourceManager.GetString("ExemplarsDialogCloseButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Details. - /// - public static string ExemplarsDialogDetailsColumnHeader { + public static string FilterDialogFieldPlaceholder { get { - return ResourceManager.GetString("ExemplarsDialogDetailsColumnHeader", resourceCulture); + return ResourceManager.GetString("FilterDialogFieldPlaceholder", resourceCulture); } } - /// - /// Looks up a localized string similar to Timestamp. - /// - public static string ExemplarsDialogTimestampColumnHeader { + public static string FilterDialogTextValuePlaceholder { get { - return ResourceManager.GetString("ExemplarsDialogTimestampColumnHeader", resourceCulture); + return ResourceManager.GetString("FilterDialogTextValuePlaceholder", resourceCulture); } } - /// - /// Looks up a localized string similar to Exemplars. - /// - public static string ExemplarsDialogTitle { + public static string FilterDialogCancelButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTitle", resourceCulture); + return ResourceManager.GetString("FilterDialogCancelButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string ExemplarsDialogTrace { + public static string FilterDialogApplyFilterButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTrace", resourceCulture); + return ResourceManager.GetString("FilterDialogApplyFilterButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Trace. - /// - public static string ExemplarsDialogTraceColumnHeader { + public static string FilterDialogRemoveFilterButtonText { get { - return ResourceManager.GetString("ExemplarsDialogTraceColumnHeader", resourceCulture); + return ResourceManager.GetString("FilterDialogRemoveFilterButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string ExemplarsDialogValueColumnHeader { + public static string SettingsDialogSystemTheme { get { - return ResourceManager.GetString("ExemplarsDialogValueColumnHeader", resourceCulture); + return ResourceManager.GetString("SettingsDialogSystemTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Apply filter. - /// - public static string FilterDialogApplyFilterButtonText { + public static string SettingsDialogLightTheme { get { - return ResourceManager.GetString("FilterDialogApplyFilterButtonText", resourceCulture); + return ResourceManager.GetString("SettingsDialogLightTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Cancel. - /// - public static string FilterDialogCancelButtonText { + public static string SettingsDialogDarkTheme { get { - return ResourceManager.GetString("FilterDialogCancelButtonText", resourceCulture); + return ResourceManager.GetString("SettingsDialogDarkTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Condition. - /// - public static string FilterDialogConditionInputLabel { + public static string SettingsDialogTheme { get { - return ResourceManager.GetString("FilterDialogConditionInputLabel", resourceCulture); + return ResourceManager.GetString("SettingsDialogTheme", resourceCulture); } } - /// - /// Looks up a localized string similar to Field. - /// - public static string FilterDialogFieldPlaceholder { + public static string SettingsDialogVersion { get { - return ResourceManager.GetString("FilterDialogFieldPlaceholder", resourceCulture); + return ResourceManager.GetString("SettingsDialogVersion", resourceCulture); } } - /// - /// Looks up a localized string similar to Parameter. - /// public static string FilterDialogParameterInputLabel { get { return ResourceManager.GetString("FilterDialogParameterInputLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Remove filter. - /// - public static string FilterDialogRemoveFilterButtonText { + public static string FilterDialogConditionInputLabel { get { - return ResourceManager.GetString("FilterDialogRemoveFilterButtonText", resourceCulture); + return ResourceManager.GetString("FilterDialogConditionInputLabel", resourceCulture); } } - /// - /// Looks up a localized string similar to Value. - /// - public static string FilterDialogTextValuePlaceholder { + public static string HelpDialogGetHelpLinkText { get { - return ResourceManager.GetString("FilterDialogTextValuePlaceholder", resourceCulture); + return ResourceManager.GetString("HelpDialogGetHelpLinkText", resourceCulture); } } - /// - /// Looks up a localized string similar to Site-wide navigation. - /// - public static string HelpDialogCategoryNavigation { + public static string HelpDialogCategoryPanels { get { - return ResourceManager.GetString("HelpDialogCategoryNavigation", resourceCulture); + return ResourceManager.GetString("HelpDialogCategoryPanels", resourceCulture); } } - /// - /// Looks up a localized string similar to Page navigation. - /// public static string HelpDialogCategoryPageNavigation { get { return ResourceManager.GetString("HelpDialogCategoryPageNavigation", resourceCulture); } } - /// - /// Looks up a localized string similar to Panels. - /// - public static string HelpDialogCategoryPanels { + public static string HelpDialogCategoryNavigation { get { - return ResourceManager.GetString("HelpDialogCategoryPanels", resourceCulture); + return ResourceManager.GetString("HelpDialogCategoryNavigation", resourceCulture); } } - /// - /// Looks up a localized string similar to Decrease panel size. - /// - public static string HelpDialogDecreasePanelSize { + public static string HelpDialogIncreasePanelSize { get { - return ResourceManager.GetString("HelpDialogDecreasePanelSize", resourceCulture); + return ResourceManager.GetString("HelpDialogIncreasePanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Microsoft Learn documentation. - /// - public static string HelpDialogGetHelpLinkText { + public static string HelpDialogDecreasePanelSize { get { - return ResourceManager.GetString("HelpDialogGetHelpLinkText", resourceCulture); + return ResourceManager.GetString("HelpDialogDecreasePanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Console Logs. - /// - public static string HelpDialogGoToConsoleLogs { + public static string HelpDialogResetPanelSize { get { - return ResourceManager.GetString("HelpDialogGoToConsoleLogs", resourceCulture); + return ResourceManager.GetString("HelpDialogResetPanelSize", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Help. - /// - public static string HelpDialogGoToHelp { + public static string HelpDialogTogglePanelOrientation { get { - return ResourceManager.GetString("HelpDialogGoToHelp", resourceCulture); + return ResourceManager.GetString("HelpDialogTogglePanelOrientation", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Metrics. - /// - public static string HelpDialogGoToMetrics { + public static string HelpDialogTogglePanelOpen { get { - return ResourceManager.GetString("HelpDialogGoToMetrics", resourceCulture); + return ResourceManager.GetString("HelpDialogTogglePanelOpen", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Resources. - /// public static string HelpDialogGoToResources { get { return ResourceManager.GetString("HelpDialogGoToResources", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Settings. - /// - public static string HelpDialogGoToSettings { + public static string HelpDialogGoToConsoleLogs { get { - return ResourceManager.GetString("HelpDialogGoToSettings", resourceCulture); + return ResourceManager.GetString("HelpDialogGoToConsoleLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Structured Logs. - /// public static string HelpDialogGoToStructuredLogs { get { return ResourceManager.GetString("HelpDialogGoToStructuredLogs", resourceCulture); } } - /// - /// Looks up a localized string similar to Go to Traces. - /// public static string HelpDialogGoToTraces { get { return ResourceManager.GetString("HelpDialogGoToTraces", resourceCulture); } } - /// - /// Looks up a localized string similar to Increase panel size. - /// - public static string HelpDialogIncreasePanelSize { + public static string HelpDialogGoToMetrics { get { - return ResourceManager.GetString("HelpDialogIncreasePanelSize", resourceCulture); + return ResourceManager.GetString("HelpDialogGoToMetrics", resourceCulture); + } + } + + public static string HelpDialogGoToHelp { + get { + return ResourceManager.GetString("HelpDialogGoToHelp", resourceCulture); + } + } + + public static string HelpDialogGoToSettings { + get { + return ResourceManager.GetString("HelpDialogGoToSettings", resourceCulture); } } - /// - /// Looks up a localized string similar to Keyboard Shortcuts. - /// public static string HelpDialogKeyboardShortcutsTitle { get { return ResourceManager.GetString("HelpDialogKeyboardShortcutsTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Reset panel sizes. - /// - public static string HelpDialogResetPanelSize { + public static string ExemplarsDialogCloseButtonText { get { - return ResourceManager.GetString("HelpDialogResetPanelSize", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogCloseButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Close panel. - /// - public static string HelpDialogTogglePanelOpen { + public static string ExemplarsDialogTitle { get { - return ResourceManager.GetString("HelpDialogTogglePanelOpen", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTitle", resourceCulture); } } - /// - /// Looks up a localized string similar to Toggle panel orientation. - /// - public static string HelpDialogTogglePanelOrientation { + public static string ExemplarsDialogTraceColumnHeader { get { - return ResourceManager.GetString("HelpDialogTogglePanelOrientation", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTraceColumnHeader", resourceCulture); } } - /// - /// Looks up a localized string similar to Cancel. - /// - public static string OpenTraceDialogCancelButtonText { + public static string ExemplarsDialogTimestampColumnHeader { get { - return ResourceManager.GetString("OpenTraceDialogCancelButtonText", resourceCulture); + return ResourceManager.GetString("ExemplarsDialogTimestampColumnHeader", resourceCulture); + } + } + + public static string ExemplarsDialogValueColumnHeader { + get { + return ResourceManager.GetString("ExemplarsDialogValueColumnHeader", resourceCulture); + } + } + + public static string ExemplarsDialogDetailsColumnHeader { + get { + return ResourceManager.GetString("ExemplarsDialogDetailsColumnHeader", resourceCulture); + } + } + + public static string ExemplarsDialogTrace { + get { + return ResourceManager.GetString("ExemplarsDialogTrace", resourceCulture); } } - /// - /// Looks up a localized string similar to Waiting for trace {0} to load.... - /// public static string OpenTraceDialogMessage { get { return ResourceManager.GetString("OpenTraceDialogMessage", resourceCulture); } } - /// - /// Looks up a localized string similar to Dark. - /// - public static string SettingsDialogDarkTheme { + public static string OpenTraceDialogCancelButtonText { get { - return ResourceManager.GetString("SettingsDialogDarkTheme", resourceCulture); + return ResourceManager.GetString("OpenTraceDialogCancelButtonText", resourceCulture); } } - /// - /// Looks up a localized string similar to Light. - /// - public static string SettingsDialogLightTheme { + public static string TextVisualizerDialogPlaintextFormat { get { - return ResourceManager.GetString("SettingsDialogLightTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogPlaintextFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to System. - /// - public static string SettingsDialogSystemTheme { + public static string TextVisualizerDialogJsonFormat { get { - return ResourceManager.GetString("SettingsDialogSystemTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogJsonFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to Theme. - /// - public static string SettingsDialogTheme { + public static string TextVisualizerDialogXmlFormat { get { - return ResourceManager.GetString("SettingsDialogTheme", resourceCulture); + return ResourceManager.GetString("TextVisualizerDialogXmlFormat", resourceCulture); } } - /// - /// Looks up a localized string similar to Version: {0}. - /// - public static string SettingsDialogVersion { + public static string TextVisualizerSelectFormatType { get { - return ResourceManager.GetString("SettingsDialogVersion", resourceCulture); + return ResourceManager.GetString("TextVisualizerSelectFormatType", resourceCulture); + } + } + + public static string OpenInTextVisualizer { + get { + return ResourceManager.GetString("OpenInTextVisualizer", resourceCulture); } } } From 813cb75ef1206921f219b60b91365e092fa91d9a Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Thu, 1 Aug 2024 12:42:03 -0400 Subject: [PATCH 15/25] Update ThemeManager to obtain effective theme, conditionally highlight in light or dark mode based on effective theme --- src/Aspire.Dashboard/Components/App.razor | 1 + .../Dialogs/TextVisualizerDialog.razor | 3 - .../Dialogs/TextVisualizerDialog.razor.cs | 13 +- .../Dialogs/TextVisualizerDialog.razor.js | 4 +- .../Components/Layout/MainLayout.razor | 10 + .../Components/Layout/MainLayout.razor.cs | 9 + .../Extensions/FluentUIExtensions.cs | 13 +- src/Aspire.Dashboard/Model/ThemeManager.cs | 10 +- .../css/highlight-11.10.0-a11y-dark-min.css | 7 + .../css/highlight-11.10.0-a11y-light-min.css | 7 + .../css/highlight-11.10.0-default.min.css | 9 - src/Aspire.Dashboard/wwwroot/js/app-theme.js | 14 +- .../wwwroot/js/highlight-11.10.0.min.js | 2388 ++++++++--------- src/Shared/StringComparers.cs | 1 + 14 files changed, 1256 insertions(+), 1233 deletions(-) create mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-a11y-dark-min.css create mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-a11y-light-min.css delete mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-default.min.css diff --git a/src/Aspire.Dashboard/Components/App.razor b/src/Aspire.Dashboard/Components/App.razor index 1d82c5e648a..1d9ae7c87dd 100644 --- a/src/Aspire.Dashboard/Components/App.razor +++ b/src/Aspire.Dashboard/Components/App.razor @@ -10,6 +10,7 @@ + /,{relevance:10}),{begin://, -relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, -relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ -end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ -end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ -className:"tag",begin:/<>|<\/>/},{className:"tag", -begin:n.concat(//,/>/,/\s/)))), -end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ -className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ -className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} -},grmr_yaml:e=>{ -const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ -end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, -end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", -contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ -begin:/\w[\w :()\./-]*:(?=[ \t]|$)/},{begin:/"\w[\w :()\./-]*":(?=[ \t]|$)/},{ -begin:/'\w[\w :()\./-]*':(?=[ \t]|$)/}]},{className:"meta",begin:"^---\\s*$", -relevance:10},{className:"string", -begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", -begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] -;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, -aliases:["yml"],contains:l}}});const Ke=te;for(const e of Object.keys(Pe)){ -const n=e.replace("grmr_","").replace("_","-");Ke.registerLanguage(n,Pe[e])} -return Ke}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file + begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} + ;Object.assign(t,{className:"variable",variants:[{ + begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ + className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE] + },r=e.inherit(e.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),s={ + begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, + end:/(\w+)/,className:"string"})]}},o={className:"string",begin:/"/,end:/"/, + contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(o);const l={begin:/\$?\(\(/, + end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] + },c=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 + }),d={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, + contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ + name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, + keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], + literal:["true","false"], + built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] + },contains:[c,e.SHEBANG(),d,l,r,s,{match:/(\/[a-z._-]+)+/},o,{match:/\\"/},{ + className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}},grmr_c:e=>{ + const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] + }),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ + className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ + match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ + begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ + begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", + end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ + begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ + className:"number",variants:[{begin:"\\b(0b[01']+)"},{ + begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" + },{ + begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" + }],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ + keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef elifdef elifndef include" + },contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ + className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ + className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 + },g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ + keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","typeof","typeof_unqual","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], + type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_BitInt","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal96","_Decimal128","_Decimal64x","_Decimal128x","_Float16","_Float32","_Float64","_Float128","_Float32x","_Float64x","_Float128x","const","static","constexpr","complex","bool","imaginary"], + literal:"true false NULL", + built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" + },b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ + begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], + keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, + contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ + begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, + keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ + begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], + relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, + keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, + end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] + }]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, + disableAutodetect:!0,illegal:"=]/,contains:[{ + beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, + strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ + contains:[{begin:/\\\n/}] + }),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ + className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ + begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ + begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", + end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ + begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ + className:"number",variants:[{ + begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)" + },{ + begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)" + }],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ + keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" + },contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ + className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ + className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 + },g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ + type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], + keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], + literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], + _type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] + },b={className:"function.dispatch",relevance:0,keywords:{ + _hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] + }, + begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) + },m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ + begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], + keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, + contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", + begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, + keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ + begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ + begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ + className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, + contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, + relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] + },s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", + aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ + match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], + className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ + keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), + built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], + literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ + begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ + begin:"\\b(0b[01']+)"},{ + begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ + begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" + }],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] + },r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, + keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, + end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ + },e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ + begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, + contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) + ;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], + o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ + illegal:/\n/})];const g={variants:[{className:"string", + begin:/"""("*)(?!")(.|\n)*?"""\1/,relevance:1 + },c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},u={begin:"<",end:">", + contains:[{beginKeywords:"in out"},t] + },b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ + begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], + keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, + contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ + begin:"\x3c!--|--\x3e"},{begin:""}]}] + }),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", + end:"$",keywords:{ + keyword:"if else elif endif define undef warning error line region endregion pragma checksum" + }},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, + illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" + },t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", + relevance:0,end:/[{;=]/,illegal:/[^\s:]/, + contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ + beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, + contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", + begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ + className:"string",begin:/"/,end:/"/}]},{ + beginKeywords:"new return throw await else",relevance:0},{className:"function", + begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, + end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ + beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", + relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, + contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", + begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, + contains:[g,a,e.C_BLOCK_COMMENT_MODE] + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ + const n=e.regex,t=ae(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ + name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ + keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, + contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ + },t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 + },{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 + },t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ + begin:":("+se.join("|")+")"},{begin:":(:)?("+oe.join("|")+")"}] + },t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+le.join("|")+")\\b"},{ + begin:/:/,end:/[;}{]/, + contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ + begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" + },contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, + excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", + relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ + },{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ + $pattern:/[a-z-]+/,keyword:"and or not only",attribute:re.join(" ")},contains:[{ + begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ + className:"selector-tag",begin:"\\b("+ie.join("|")+")\\b"}]}},grmr_diff:e=>{ + const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ + className:"meta",relevance:10, + match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) + },{className:"comment",variants:[{ + begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), + end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ + className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, + end:/$/}]}},grmr_go:e=>{const n={ + keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], + type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], + literal:["true","false","iota","nil"], + built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] + };return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex + ;return{name:"GraphQL",aliases:["gql"],case_insensitive:!0,disableAutodetect:!1, + keywords:{ + keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], + literal:["true","false","null"]}, + contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ + scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", + begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, + end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ + scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), + relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ + className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ + begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, + end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ + begin:/\$\{(.*?)\}/}]},r={className:"literal", + begin:/\bon|off|true|false|yes|no\b/},s={className:"string", + contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ + begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] + },o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 + },l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ + name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, + contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ + begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), + className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ + const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+me("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ + keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits","goto"], + literal:["false","true","null"], + type:["char","boolean","long","float","int","byte","short","double"], + built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ + begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, + end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} + ;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, + contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, + relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ + begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, + className:"string",contains:[e.BACKSLASH_ESCAPE] + },e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ + match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ + 1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ + begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", + 3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", + 3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ + beginKeywords:"new throw return else",relevance:0},{ + begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ + 2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, + end:/\)/,keywords:i,relevance:0, + contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,be,e.C_BLOCK_COMMENT_MODE] + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},be,r]}},grmr_javascript:ve, + grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", + beginKeywords:n.join(" ")};return{name:"JSON",aliases:["jsonc"],keywords:{ + literal:n},contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/, + relevance:1.01},{match:/[{}[\],:]/,className:"punctuation",relevance:0 + },e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], + illegal:"\\S"}},grmr_kotlin:e=>{const n={ + keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", + built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", + literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" + },a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ + className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", + variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", + illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, + contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ + className:"meta", + begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" + },o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, + end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] + },l=be,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ + variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, + contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], + {name:"Kotlin",aliases:["kt","kts"],keywords:n, + contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", + begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", + begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", + begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", + returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ + begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, + contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, + keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, + endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, + endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 + },e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ + begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ + 3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, + illegal:"extends implements",contains:[{ + beginKeywords:"public protected internal private constructor" + },e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, + excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, + excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", + end:"$",illegal:"\n"},l]}},grmr_less:e=>{ + const n=ae(e),t=ce,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ + className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, + relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", + attribute:re.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, + relevance:0} + ;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ + begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", + excludeEnd:!0} + },n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ + className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 + },n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ + begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, + contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", + returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ + },n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+le.join("|")+")\\b", + end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] + },m={className:"keyword", + begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", + starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ + className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a + }],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ + begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, + returnEnd:!0,illegal:"[<='$\"]",relevance:0, + contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ + begin:"\\b("+ie.join("|")+")\\b",className:"selector-tag" + },n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ + className:"selector-pseudo",begin:":("+se.join("|")+")"},{ + className:"selector-pseudo",begin:":(:)?("+oe.join("|")+")"},{begin:/\(/, + end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ + begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} + ;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), + {name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, + grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] + },i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 + })];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, + literal:"true false nil", + keyword:"and break do else elseif end for goto if in local not or repeat return then until while", + built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" + },contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", + contains:[e.inherit(e.TITLE_MODE,{ + begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", + begin:"\\(",endsWithParent:!0,contains:i}].concat(i) + },e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", + begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ + className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", + contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ + const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ + variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ + begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, + relevance:2},{ + begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), + relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ + begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ + },{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, + returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", + excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", + end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], + variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] + },i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ + begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] + }),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) + ;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) + })),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ + className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ + begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", + contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", + end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, + end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ + begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ + begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", + contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ + begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ + className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ + className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},{scope:"literal", + match:/&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/}]}}, + grmr_objectivec:e=>{const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, + keyword:["@interface","@class","@protocol","@implementation"]};return{ + name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], + keywords:{"variable.language":["this","super"],$pattern:n, + keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], + literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], + built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], + type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] + },illegal:"/,end:/$/,illegal:"\\n" + },e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", + begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, + contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, + relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ + $pattern:/[\w.]+/, + keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot class close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl field fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map method mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" + },i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, + end:/\}/},s={scope:"attr",match:/\s+:\s*\w+(\s*\(.*?\))?/},o={scope:"variable", + variants:[{begin:/\$\d/},{ + begin:n.concat(/[$%@](?!")(\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") + },{begin:/[$%@](?!")[^\s\w{=]|\$=/,relevance:0}],contains:[s]},l={ + className:"number",variants:[{match:/0?\.[0-9][0-9_]+\b/},{ + match:/\bv?(0|[1-9][0-9_]*(\.[0-9_]+)?|[1-9][0-9_]*)\b/},{ + match:/\b0[0-7][0-7_]*\b/},{match:/\b0x[0-9a-fA-F][0-9a-fA-F_]*\b/},{ + match:/\b0b[0-1][0-1_]*\b/}],relevance:0 + },c=[e.BACKSLASH_ESCAPE,i,o],d=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],g=(e,a,i="\\1")=>{ + const r="\\1"===i?i:n.concat(i,a) + ;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) + },u=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),b=[o,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ + endsWithParent:!0}),r,{className:"string",contains:c,variants:[{ + begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", + end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ + begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", + relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", + contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", + contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ + begin:"-?\\w+\\s*=>",relevance:0}]},l,{ + begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", + keywords:"split return print reverse grep",relevance:0, + contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ + begin:g("s|tr|y",n.either(...d,{capture:!0}))},{begin:g("s|tr|y","\\(","\\)")},{ + begin:g("s|tr|y","\\[","\\]")},{begin:g("s|tr|y","\\{","\\}")}],relevance:2},{ + className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ + begin:u("(?:m|qr)?",/\//,/\//)},{begin:u("m|qr",n.either(...d,{capture:!0 + }),/\1/)},{begin:u("m|qr",/\(/,/\)/)},{begin:u("m|qr",/\[/,/\]/)},{ + begin:u("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub method", + end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE,s] + },{className:"class",beginKeywords:"class",end:"[;{]",excludeEnd:!0,relevance:5, + contains:[e.TITLE_MODE,s,l]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$", + end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$", + className:"comment"}]}];return i.contains=b,r.contains=b,{name:"Perl", + aliases:["pl","pm"],keywords:a,contains:b}},grmr_php:e=>{ + const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ + scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ + begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null + }),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ + illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ + begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, + contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ + n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ + n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ + begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ + begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ + begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ + begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" + }],relevance:0 + },g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ + keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ + n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) + })),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ + match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ + 1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ + match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" + }},{match:[/::/,/class/],scope:{2:"variable.language"}},{ + match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", + 3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], + scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", + 3:"variable.language"}}]},E={scope:"attr", + match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, + begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] + },w={relevance:0, + match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], + scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(w) + ;const N=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, + keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, + endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ + begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, + contains:["self",...N]},...N,{scope:"meta",match:i}] + },e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ + scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, + keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, + contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ + begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ + begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,w,f,{ + match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ + scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, + excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" + },e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", + begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, + contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ + beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", + illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ + beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ + beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, + contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ + beginKeywords:"use",relevance:0,end:";",contains:[{ + match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} + },grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ + begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", + end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 + },e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, + skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, + contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", + aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ + const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ + $pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, + built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], + literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], + type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] + },r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, + end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ + className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ + begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, + contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ + begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, + contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ + begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, + contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, + end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, + relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ + begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, + end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, + contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, + contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] + },c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ + className:"number",relevance:0,variants:[{ + begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ + begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ + begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` + },{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` + }]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, + contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ + className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, + end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, + contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ + name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, + illegal:/(<\/|\?)|=>/,contains:[r,u,{scope:"variable.language",match:/\bself\b/ + },{beginKeywords:"if",relevance:0},{match:/\bor\b/,scope:"keyword" + },l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{1:"keyword", + 3:"title.function"},contains:[m]},{variants:[{ + match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], + scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ + className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, + grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", + starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ + begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ + const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) + ;return{name:"R",keywords:{$pattern:t, + keyword:"function if in break next repeat else for while", + literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", + built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" + },contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, + starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), + endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ + scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 + }]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] + }),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], + variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ + }),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', + relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ + 1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, + match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ + 2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, + match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ + match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", + contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ + const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ + "variable.constant":["__FILE__","__LINE__","__ENCODING__"], + "variable.language":["self","super"], + keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], + built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], + literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ + begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] + }),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 + }),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, + end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], + variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ + begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ + begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, + end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ + begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ + begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ + begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ + begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ + begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), + contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, + contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", + relevance:0,variants:[{ + begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ + begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" + },{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ + begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ + begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ + className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, + keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ + match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", + 4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ + 2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ + 1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, + className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ + match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ + begin:e.IDENT_RE+"::"},{className:"symbol", + begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", + begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", + begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ + className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, + relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", + keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], + illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ + begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", + end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) + ;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} + },{className:"meta.prompt", + begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", + starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", + aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, + contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, + grmr_rust:e=>{ + const n=e.regex,t=/(r#)?/,a=n.concat(t,e.UNDERSCORE_IDENT_RE),i=n.concat(t,e.IDENT_RE),r={ + className:"title.function.invoke",relevance:0, + begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,i,n.lookahead(/\s*\(/)) + },s="([ui](8|16|32|64|128|size)|f(32|64))?",o=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],l=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] + ;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:l, + keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","union","unsafe","unsized","use","virtual","where","while","yield"], + literal:["true","false","Some","None","Ok","Err"],built_in:o},illegal:""},r]}}, + grmr_scss:e=>{const n=ae(e),t=oe,a=se,i="@[a-z-]+",r={className:"variable", + begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", + case_insensitive:!0,illegal:"[=/|']", + contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ + className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ + className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 + },n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", + begin:"\\b("+ie.join("|")+")\\b",relevance:0},{className:"selector-pseudo", + begin:":("+a.join("|")+")"},{className:"selector-pseudo", + begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, + contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", + begin:"\\b("+le.join("|")+")\\b"},{ + begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" + },{begin:/:/,end:/[;}{]/,relevance:0, + contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] + },{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ + begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, + keyword:"and or not only",attribute:re.join(" ")},contains:[{begin:i, + className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" + },r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] + },n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", + aliases:["console","shellsession"],contains:[{className:"meta.prompt", + begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, + subLanguage:"bash"}}]}),grmr_sql:e=>{ + const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ + begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} + ;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ + $pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t + ;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) + })(l,{when:e=>e.length<3}),literal:a,type:i, + built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] + },contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, + keyword:l.concat(s),literal:a,type:i}},{className:"type", + begin:n.either("double precision","large object","with timezone","without timezone") + },c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", + variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, + contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ + className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, + relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 + },t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ + match:[/\./,m(...xe,...Oe)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), + relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ + className:"keyword", + match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Me).map(ke),...Oe)}]},l={ + $pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Te),literal:Se},c=[i,r,o],g=[{ + match:b(/\./,m(...Re)),relevance:0},{className:"built_in", + match:b(/\b/,m(...Re),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ + className:"operator",relevance:0,variants:[{match:Le},{match:`\\.(\\.|${Ie})+`}] + }],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, + variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ + match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ + },{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ + match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] + }),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) + }),w=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ + }),N=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),w(e)] + }),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),w(e)]}),k={ + className:"string", + variants:[N(),N("#"),N("##"),N("###"),v(),v("#"),v("##"),v("###")] + },x=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, + contains:[e.BACKSLASH_ESCAPE]}],O={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, + contains:x},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, + contains:[...x,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},A={ + scope:"regexp",variants:[M("###"),M("##"),M("#"),O]},S={match:b(/`/,Fe,/`/) + },C=[S,{className:"variable",match:/\$\d+/},{className:"variable", + match:`\\$${$e}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ + contains:[{begin:/\(/,end:/\)/,keywords:je,contains:[...p,f,k]}]}},{ + scope:"keyword",match:b(/@/,m(...Ue),d(m(/\(/,/\s+/)))},{scope:"meta", + match:b(/@/,Fe)}],R={match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", + match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,$e,"+") + },{className:"type",match:ze,relevance:0},{match:/[?!]+/,relevance:0},{ + match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(ze)),relevance:0}]},D={ + begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) + ;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ + match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 + },...a,A,...c,...g,...p,f,k,...C,...T,R]},L={begin://, + keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, + contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, + relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", + match:Fe}]},...a,...c,...p,f,k,...T,R,I],endsParent:!0,illegal:/["']/},$={ + match:[/(func|macro)/,/\s+/,m(S.match,Fe,Le)],className:{1:"keyword", + 3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},F={ + match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, + contains:[L,B,n],illegal:/\[|%/},z={match:[/operator/,/\s+/,Le],className:{ + 1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,ze],className:{ + 1:"keyword",3:"title"},contains:[R],keywords:[...Ce,...Se],end:/}/},j={ + begin:[/(struct|protocol|class|extension|enum|actor)/,/\s+/,Fe,/\s*/], + beginScope:{1:"keyword",3:"title.class"},keywords:l,contains:[L,...c,{begin:/:/, + end:/\{/,keywords:l,contains:[{scope:"title.class.inherited",match:ze},...c], + relevance:0}]};for(const e of k.variants){ + const n=e.contains.find((e=>"interpol"===e.label));n.keywords=l + ;const t=[...c,...g,...p,f,k,...C];n.contains=[...t,{begin:/\(/,end:/\)/, + contains:["self",...t]}]}return{name:"Swift",keywords:l, + contains:[...a,$,F,j,z,U,{beginKeywords:"import",end:/$/,contains:[...a], + relevance:0},A,...c,...g,...p,f,k,...C,...T,R,I]}},grmr_typescript:e=>{ + const n=ve(e),t=pe,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ + begin:[/namespace/,/\s+/,e.IDENT_RE],beginScope:{1:"keyword",3:"title.class"} + },r={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{ + keyword:"interface extends",built_in:a},contains:[n.exports.CLASS_REFERENCE] + },s={$pattern:pe, + keyword:_e.concat(["type","interface","public","private","protected","implements","declare","abstract","readonly","enum","override","satisfies"]), + literal:he,built_in:Ne.concat(a),"variable.language":we},o={className:"meta", + begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) + ;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} + ;Object.assign(n.keywords,s),n.exports.PARAMS_CONTAINS.push(o) + ;const c=n.contains.find((e=>"attr"===e.className)) + ;return n.exports.PARAMS_CONTAINS.push([n.exports.CLASS_REFERENCE,c]), + n.contains=n.contains.concat([o,i,r]), + l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, + begin:/^\s*['"]use strict['"]/ + }),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ + name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ + const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ + className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ + begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ + begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] + },o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] + }),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) + ;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, + classNameAliases:{label:"symbol"},keywords:{ + keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", + built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", + type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", + literal:"true false nothing"}, + illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ + className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, + end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, + variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ + },{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ + begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ + className:"label",begin:/^\w+:/},o,l,{className:"meta", + begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, + end:/$/,keywords:{ + keyword:"const disable else elseif enable end externalsource if region then"}, + contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) + ;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, + keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] + },contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], + className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ + match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ + begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", + 3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, + className:"type"},{className:"keyword", + match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ + },{className:"number",relevance:0, + match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ + }]}},grmr_xml:e=>{ + const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ + className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, + contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] + },r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ + className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ + endsWithParent:!0,illegal:/`]+/}]}]}]};return{ + name:"HTML, XML", + aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], + case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ + className:"meta",begin://,contains:[i,r,o,s]}]}] + },e.COMMENT(//,{relevance:10}),{begin://, + relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, + relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", + begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ + end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", + begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ + end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ + className:"tag",begin:/<>|<\/>/},{className:"tag", + begin:n.concat(//,/>/,/\s/)))), + end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ + className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ + className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} + },grmr_yaml:e=>{ + const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ + className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ + },{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", + variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ + variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ + end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, + end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", + contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ + begin:/\w[\w :()\./-]*:(?=[ \t]|$)/},{begin:/"\w[\w :()\./-]*":(?=[ \t]|$)/},{ + begin:/'\w[\w :()\./-]*':(?=[ \t]|$)/}]},{className:"meta",begin:"^---\\s*$", + relevance:10},{className:"string", + begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ + begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, + relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", + begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t + },{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", + begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", + relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ + className:"number", + begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" + },{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] + ;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, + aliases:["yml"],contains:l}}});const Ke=te;for(const e of Object.keys(Pe)){ + const n=e.replace("grmr_","").replace("_","-");Ke.registerLanguage(n,Pe[e])} +export{Ke as default}; diff --git a/src/Shared/StringComparers.cs b/src/Shared/StringComparers.cs index 6126b0fcd25..15ac86e0c7e 100644 --- a/src/Shared/StringComparers.cs +++ b/src/Shared/StringComparers.cs @@ -15,6 +15,7 @@ internal static class StringComparers public static StringComparer EnvironmentVariableName => StringComparer.InvariantCultureIgnoreCase; public static StringComparer UrlPath => StringComparer.OrdinalIgnoreCase; public static StringComparer UrlHost => StringComparer.OrdinalIgnoreCase; + public static StringComparer Attribute => StringComparer.Ordinal; } internal static class StringComparisons From 665b30b23848e95f4f17a6a4df63d060ef4f6470 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Thu, 1 Aug 2024 15:06:27 -0400 Subject: [PATCH 16/25] remove unnecessary top margin, re-highlight if container content has changed --- .../Components/Controls/LogViewer.razor.css | 1 + .../Dialogs/TextVisualizerDialog.razor | 14 +++--- .../Dialogs/TextVisualizerDialog.razor.cs | 50 +++++++++++++------ .../Dialogs/TextVisualizerDialog.razor.js | 28 +++++++---- src/Aspire.Dashboard/wwwroot/css/app.css | 1 - 5 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css index f66f8c6cf57..1297f3c4b6b 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css @@ -1,6 +1,7 @@ ::deep .console-container { background: var(--console-background-color); color: var(--console-font-color); + margin: 16px 0 0 0; } ::deep .console-line-row:hover { diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index 647a122cb50..ab16a657e3d 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -17,7 +17,7 @@ @foreach (var option in _options) @@ -30,16 +30,18 @@ -
-
- +
+
+
@context.LineNumber @if (context.IsFormatted) { - + // data-content and data-language used in javascript when re-highlighting a node when its + // content changes (through scrolling) + @context.Content } @@ -58,7 +60,7 @@ + AdditionalAttributes="@FluentUIExtensions.GetClipboardCopyAdditionalAttributes(FormattedText, ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)], ControlsStringsLoc[nameof(ControlsStrings.GridValueCopied)])">
+ + + + + + @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] + -
+
@@ -56,18 +67,6 @@
- - - - - - - @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] -
diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs index 58e5c7a3a14..5fb0a5c02b5 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.cs @@ -98,7 +98,7 @@ private ICollection GetLines() { var lines = FormattedText.Split(["\r\n", "\r", "\n"], StringSplitOptions.None).ToList(); - return lines.Select((line, index) => new StringLogLine(index, line, FormatKind != PlaintextFormat)).ToList(); + return lines.Select((line, index) => new StringLogLine(index + 1, line, FormatKind != PlaintextFormat)).ToList(); } private bool TryFormatXml() From 6cd0349e0c4b351c6c6fd991a6020de2ddaaed82 Mon Sep 17 00:00:00 2001 From: "Ratzman, Adam Mortimer" Date: Wed, 7 Aug 2024 12:56:28 -0400 Subject: [PATCH 19/25] change width/height display of dialog --- .../Components/Controls/GridValue.razor | 4 +-- .../Dialogs/TextVisualizerDialog.razor | 27 +++++++++---------- .../Dialogs/TextVisualizerDialog.razor.css | 6 ----- .../Components/Layout/MainLayout.razor.cs | 4 +-- src/Aspire.Dashboard/wwwroot/css/app.css | 2 +- 5 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/GridValue.razor b/src/Aspire.Dashboard/Components/Controls/GridValue.razor index db70a3a6b71..947162be51f 100644 --- a/src/Aspire.Dashboard/Components/Controls/GridValue.razor +++ b/src/Aspire.Dashboard/Components/Controls/GridValue.razor @@ -1,5 +1,4 @@ -@using Aspire.Dashboard.Extensions -@using Aspire.Dashboard.Resources +@using Aspire.Dashboard.Resources @inject IStringLocalizer Loc @inject IStringLocalizer DialogsLoc @@ -76,3 +75,4 @@
+
diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index 91379a75fa0..2b6e3158fe3 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -26,22 +26,11 @@ }
- - - - - - @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] - -
+
@@ -66,8 +55,18 @@
-
-
+
+ + + + + + @ControlsStringsLoc[nameof(ControlsStrings.GridValueCopyToClipboard)] + diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css index 4c112cdd531..d9576f0da08 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css @@ -2,12 +2,6 @@ user-select: none; } -::deep .text-visualizer-copy-button { - position: absolute; - right: calc(var(--design-unit) * 4px); - bottom: calc(var(--design-unit) * 4px); -} - ::deep .highlight-line { width: 100%; background: transparent; diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index af988d3e461..86ebd4019e5 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -264,11 +264,11 @@ private void CloseMobileNavMenu() [JSInvokable] public async Task OpenTextVisualizerAsync(IJSStreamReference valueStream, string valueDescription) { + var width = ViewportInformation.IsDesktop ? "75vw" : "100vw"; var parameters = new DialogParameters { Title = valueDescription, - Width = ViewportInformation.IsDesktop ? "75vw" : "100vw", - Height = ViewportInformation.IsDesktop ? "75vh" : "100vh", + Width = $"min(600px, {width})", TrapFocus = true, Modal = true, PreventScroll = true, diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index b16f970e426..4e75c6d43db 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -527,13 +527,13 @@ fluent-data-grid-cell.no-ellipsis { --console-background-color-hover: #1D1D1D; --console-font-color: var(--console-theme-white); - height: 100%; width: 100%; overflow: auto; } .console-overflow { background-color: var(--console-background-color); + height: 100%; } .log-container { From 1593d0dac7ea142fda52d14e40c643c99fab8ee7 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 8 Aug 2024 14:41:35 +0800 Subject: [PATCH 20/25] Update src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs --- src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs index 86ebd4019e5..f2fb81a8240 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs @@ -268,7 +268,7 @@ public async Task OpenTextVisualizerAsync(IJSStreamReference valueStream, string var parameters = new DialogParameters { Title = valueDescription, - Width = $"min(600px, {width})", + Width = $"min(1000px, {width})", TrapFocus = true, Modal = true, PreventScroll = true, From 1892bc8e202f208440ea6e42fb509310031b910c Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 8 Aug 2024 15:13:19 +0800 Subject: [PATCH 21/25] Style fixes --- .../Components/Controls/LogViewer.razor.css | 2 +- .../Components/Dialogs/TextVisualizerDialog.razor | 2 +- .../Components/Dialogs/TextVisualizerDialog.razor.css | 2 +- src/Aspire.Dashboard/wwwroot/css/app.css | 9 ++++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css index 1297f3c4b6b..8523b4ac850 100644 --- a/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css +++ b/src/Aspire.Dashboard/Components/Controls/LogViewer.razor.css @@ -1,7 +1,7 @@ ::deep .console-container { background: var(--console-background-color); color: var(--console-font-color); - margin: 16px 0 0 0; + margin: 16px 0; } ::deep .console-line-row:hover { diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index 2b6e3158fe3..efe7c8614bd 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -30,7 +30,7 @@ -
+
diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css index d9576f0da08..b8ee81574b8 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor.css @@ -1,5 +1,5 @@ ::deep .text-visualizer-line-number { - user-select: none; + min-width: 33px; } ::deep .highlight-line { diff --git a/src/Aspire.Dashboard/wwwroot/css/app.css b/src/Aspire.Dashboard/wwwroot/css/app.css index 4e75c6d43db..ee76771d095 100644 --- a/src/Aspire.Dashboard/wwwroot/css/app.css +++ b/src/Aspire.Dashboard/wwwroot/css/app.css @@ -539,7 +539,6 @@ fluent-data-grid-cell.no-ellipsis { .log-container { font-family: 'Cascadia Mono', Consolas, monospace; font-size: 13px; - padding-bottom: 24px; line-height: 20px; overflow: visible; display: flex; @@ -554,7 +553,7 @@ fluent-data-grid-cell.no-ellipsis { .log-line-row { cursor: text; - padding: 0 12px 0 12px; + padding: 0 12px 0 0; white-space: pre-wrap; display: flex; @@ -569,15 +568,15 @@ fluent-data-grid-cell.no-ellipsis { flex-direction: row; } -.line-number { - padding-left: 10px; - min-width: 43px; +.log-line-number { + min-width: 53px; text-align: right; align-self: flex-start; flex-shrink: 0; color: var(--line-number-color); user-select: none; cursor: default; + height: 100%; } .log-content { From bb2d8d9473d59f854d7fb3084908ecdc5840e009 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Thu, 8 Aug 2024 21:09:24 +0800 Subject: [PATCH 22/25] Change text visualizer theming from server to client side --- src/Aspire.Dashboard/Components/App.razor | 1 + .../Dialogs/TextVisualizerDialog.razor | 4 +- .../Dialogs/TextVisualizerDialog.razor.cs | 7 ++- .../Components/Layout/MainLayout.razor | 9 --- .../Components/Layout/MainLayout.razor.cs | 10 +-- .../DashboardWebApplication.cs | 1 + src/Aspire.Dashboard/Model/ThemeManager.cs | 63 +++++++++++++++++-- src/Aspire.Dashboard/wwwroot/css/app.css | 30 +++++---- .../css/highlight-11.10.0-a11y-dark-min.css | 7 --- .../css/highlight-11.10.0-a11y-light-min.css | 7 --- .../wwwroot/css/highlight.css | 59 +++++++++++++++++ src/Aspire.Dashboard/wwwroot/js/app-theme.js | 2 + .../Controls/TextVisualizerDialogTests.cs | 14 ++++- .../Shared/MetricsSetupHelpers.cs | 1 + .../Shared/TestEffectiveThemeResolver.cs | 14 +++++ 15 files changed, 178 insertions(+), 51 deletions(-) delete mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-a11y-dark-min.css delete mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight-11.10.0-a11y-light-min.css create mode 100644 src/Aspire.Dashboard/wwwroot/css/highlight.css create mode 100644 tests/Aspire.Dashboard.Components.Tests/Shared/TestEffectiveThemeResolver.cs diff --git a/src/Aspire.Dashboard/Components/App.razor b/src/Aspire.Dashboard/Components/App.razor index 1d9ae7c87dd..d7ef3cf0b0b 100644 --- a/src/Aspire.Dashboard/Components/App.razor +++ b/src/Aspire.Dashboard/Components/App.razor @@ -9,6 +9,7 @@ + diff --git a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor index efe7c8614bd..34c78fb7926 100644 --- a/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor +++ b/src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor @@ -55,8 +55,8 @@
-
- +
+
GetLines() diff --git a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor index 54cb83d11e3..33fd354c292 100644 --- a/src/Aspire.Dashboard/Components/Layout/MainLayout.razor +++ b/src/Aspire.Dashboard/Components/Layout/MainLayout.razor @@ -3,15 +3,6 @@ @using Aspire.Dashboard.Resources @inherits LayoutComponentBase -@if (ThemeManager.EffectiveTheme is ThemeManager.ThemeSettingDark) -{ - -} -else -{ - -} -