diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 0c7cc2a0e1..5da12c1831 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -836,6 +836,7 @@ IFilter ifndef IFolder IFormat +IFormatter ifstream IGraph iid diff --git a/src/modules/previewpane/MonacoPreviewHandler/Formatters/IFormatter.cs b/src/modules/previewpane/MonacoPreviewHandler/Formatters/IFormatter.cs new file mode 100644 index 0000000000..88bb982bc2 --- /dev/null +++ b/src/modules/previewpane/MonacoPreviewHandler/Formatters/IFormatter.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.PreviewHandler.Monaco.Formatters +{ + public interface IFormatter + { + /// + /// Gets the language to which the formatter is applied + /// + string LangSet { get; } + + /// + /// Format the value + /// + /// The value to format + /// The value formatted + string Format(string value); + } +} diff --git a/src/modules/previewpane/MonacoPreviewHandler/Formatters/JsonFormatter.cs b/src/modules/previewpane/MonacoPreviewHandler/Formatters/JsonFormatter.cs new file mode 100644 index 0000000000..b2b82f625d --- /dev/null +++ b/src/modules/previewpane/MonacoPreviewHandler/Formatters/JsonFormatter.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.PreviewHandler.Monaco.Formatters +{ + using System.Text.Json; + + public class JsonFormatter : IFormatter + { + /// + public string LangSet => "json"; + + /// + public string Format(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return string.Empty; + } + + using (var jDocument = JsonDocument.Parse(value, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip })) + { + return JsonSerializer.Serialize(jDocument, new JsonSerializerOptions { WriteIndented = true }); + } + } + } +} diff --git a/src/modules/previewpane/MonacoPreviewHandler/Formatters/XmlFormatter.cs b/src/modules/previewpane/MonacoPreviewHandler/Formatters/XmlFormatter.cs new file mode 100644 index 0000000000..a7cb976616 --- /dev/null +++ b/src/modules/previewpane/MonacoPreviewHandler/Formatters/XmlFormatter.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.PreviewHandler.Monaco.Formatters +{ + using System.Text; + using System.Xml; + + public class XmlFormatter : IFormatter + { + /// + public string LangSet => "xml"; + + /// + public string Format(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + return string.Empty; + } + + var xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(value); + + var stringBuilder = new StringBuilder(); + var xmlWriterSettings = new XmlWriterSettings() + { + OmitXmlDeclaration = xmlDocument.FirstChild.NodeType != XmlNodeType.XmlDeclaration, + Indent = true, + }; + + using (var xmlWriter = XmlWriter.Create(stringBuilder, xmlWriterSettings)) + { + xmlDocument.Save(xmlWriter); + } + + return stringBuilder.ToString(); + } + } +} diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs index acda8aa497..c900e7b6ea 100644 --- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs +++ b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs @@ -3,14 +3,16 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; +using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Forms; using Common; +using Microsoft.PowerToys.PreviewHandler.Monaco.Formatters; using Microsoft.PowerToys.PreviewHandler.Monaco.Helpers; using Microsoft.PowerToys.PreviewHandler.Monaco.Properties; using Microsoft.Web.WebView2.Core; @@ -26,6 +28,15 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco /// private readonly Settings _settings = new Settings(); + /// + /// Formatters applied before rendering the preview + /// + private readonly IReadOnlyCollection _formatters = new List + { + new JsonFormatter(), + new XmlFormatter(), + }.AsReadOnly(); + /// /// Saves if the user already navigated to the index page /// @@ -367,6 +378,23 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco { Logger.LogInfo("Starting reading requested file"); var fileContent = fileReader.ReadToEnd(); + + if (_settings.TryFormat) + { + var formatter = _formatters.SingleOrDefault(f => f.LangSet == _vsCodeLangSet); + if (formatter != null) + { + try + { + fileContent = formatter.Format(fileContent); + } + catch (Exception ex) + { + Logger.LogError($"Failed to apply formatting to {filePath}", ex); + } + } + } + fileReader.Close(); _base64FileCode = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileContent)); Logger.LogInfo("Reading requested file ended"); @@ -379,7 +407,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco _html = htmlFileReader.ReadToEnd(); htmlFileReader.Close(); Logger.LogInfo("Reading HTML source file ended"); - } + } _html = _html.Replace("[[PT_LANG]]", _vsCodeLangSet, StringComparison.InvariantCulture); _html = _html.Replace("[[PT_WRAP]]", _settings.Wrap ? "1" : "0", StringComparison.InvariantCulture); diff --git a/src/modules/previewpane/MonacoPreviewHandler/Settings.cs b/src/modules/previewpane/MonacoPreviewHandler/Settings.cs index 218895b5a8..e03cbcf409 100644 --- a/src/modules/previewpane/MonacoPreviewHandler/Settings.cs +++ b/src/modules/previewpane/MonacoPreviewHandler/Settings.cs @@ -37,6 +37,26 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco } } + /// + /// Gets a value indicating whether to try formatting the file. Set by PT settings. + /// + public bool TryFormat + { + get + { + try + { + return moduleSettings.GetSettings(PowerPreviewSettings.ModuleName).Properties.MonacoPreviewTryFormat; + } + catch (FileNotFoundException) + { + // Couldn't read the settings. + // Assume default of false. + return false; + } + } + } + /// /// Max file size for displaying (in bytes). /// diff --git a/src/settings-ui/Settings.UI.Library/PowerPreviewProperties.cs b/src/settings-ui/Settings.UI.Library/PowerPreviewProperties.cs index 67cb96ae34..eee0800e48 100644 --- a/src/settings-ui/Settings.UI.Library/PowerPreviewProperties.cs +++ b/src/settings-ui/Settings.UI.Library/PowerPreviewProperties.cs @@ -99,6 +99,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library } } + private bool monacoPreviewTryFormat; + + [JsonPropertyName("monaco-previewer-toggle-try-format")] + [JsonConverter(typeof(BoolPropertyJsonConverter))] + public bool MonacoPreviewTryFormat + { + get => monacoPreviewTryFormat; + set + { + if (value != monacoPreviewTryFormat) + { + LogTelemetryEvent(value); + monacoPreviewTryFormat = value; + } + } + } + private bool enablePdfPreview; [JsonPropertyName("pdf-previewer-toggle-setting")] diff --git a/src/settings-ui/Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs b/src/settings-ui/Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs index 7e4833dfcc..e1d3b3fe1f 100644 --- a/src/settings-ui/Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs +++ b/src/settings-ui/Settings.UI.Library/ViewModels/PowerPreviewViewModel.cs @@ -51,6 +51,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels _mdRenderIsEnabled = Settings.Properties.EnableMdPreview; _monacoRenderIsEnabled = Settings.Properties.EnableMonacoPreview; _monacoWrapText = Settings.Properties.EnableMonacoPreviewWordWrap; + _monacoPreviewTryFormat = Settings.Properties.MonacoPreviewTryFormat; _pdfRenderIsEnabled = Settings.Properties.EnablePdfPreview; _gcodeRenderIsEnabled = Settings.Properties.EnableGcodePreview; _pdfThumbnailIsEnabled = Settings.Properties.EnablePdfThumbnail; @@ -63,6 +64,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels private bool _mdRenderIsEnabled; private bool _monacoRenderIsEnabled; private bool _monacoWrapText; + private bool _monacoPreviewTryFormat; private bool _pdfRenderIsEnabled; private bool _gcodeRenderIsEnabled; private bool _svgThumbnailIsEnabled; @@ -161,6 +163,24 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels } } + public bool MonacoPreviewTryFormat + { + get + { + return _monacoPreviewTryFormat; + } + + set + { + if (_monacoPreviewTryFormat != value) + { + _monacoPreviewTryFormat = value; + Settings.Properties.MonacoPreviewTryFormat = value; + RaisePropertyChanged(); + } + } + } + public bool PDFRenderIsEnabled { get diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 04ecd5fc6d..bd2c5df0dc 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -422,21 +422,21 @@ Wait for more input before searching. This reduces interface jumpiness and system load. - Immediate plugins + Immediate plugins - - Affects the plugins that make the UI wait for their results by this amount. Recommended: 30-50 ms. + + Affects the plugins that make the UI wait for their results by this amount. Recommended: 30-50 ms. - - Background execution plugins + + Background execution plugins - - Affects the plugins that execute in the background by this amount. Recommended: 100-150 ms. + + Affects the plugins that execute in the background by this amount. Recommended: 100-150 ms. - + Fast plugin throttle (ms) ms = milliseconds - + To: Keyboard Manager mapping keys view right header @@ -2164,6 +2164,12 @@ From there, simply click on one of the supported files in the File Explorer and Enable round corners + + Applies to json and xml. Files remain unchanged. + + + Try to format the source for preview + Some characters and phrases may conflict with global queries of other plugins if you use them as activation command. diff --git a/src/settings-ui/Settings.UI/Views/PowerPreviewPage.xaml b/src/settings-ui/Settings.UI/Views/PowerPreviewPage.xaml index 93b82a92d2..f6c0387c9f 100644 --- a/src/settings-ui/Settings.UI/Views/PowerPreviewPage.xaml +++ b/src/settings-ui/Settings.UI/Views/PowerPreviewPage.xaml @@ -57,6 +57,11 @@ IsChecked="{x:Bind ViewModel.MonacoWrapText, Mode=TwoWay}" Margin="{StaticResource ExpanderSettingMargin}" IsEnabled="{x:Bind ViewModel.MonacoRenderIsEnabled, Mode=OneWay}" /> + +