mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 03:36:44 +02:00
[RegistryPreview] Adopt Monaco Editor (#35122)
This commit is contained in:
committed by
GitHub
parent
b0be69a1b7
commit
f9127b63a5
@@ -0,0 +1,64 @@
|
||||
<!doctype HTML>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Set browser to Edge-->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<!-- Set charset -->
|
||||
<meta charset="utf-8" />
|
||||
<!-- Title (normally not displayed)-->
|
||||
<title>Registry Preview Editor</title>
|
||||
<style>
|
||||
/* Fits content to window size */
|
||||
html, body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container, .monaco-editor {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.overflowingContentWidgets {
|
||||
/*Hides alert box */
|
||||
display: none !important
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Container for the editor -->
|
||||
<div id="container"></div>
|
||||
<!-- Script -->
|
||||
<script src="http://PowerToysLocalMonaco/monacoSRC/min/vs/loader.js"></script>
|
||||
<script type="module">
|
||||
import { registerAdditionalLanguages } from 'http://PowerToysLocalMonaco/monacoSpecialLanguages.js';
|
||||
import { customTokenColors } from 'http://PowerToysLocalMonaco/customTokenColors.js';
|
||||
require.config({ paths: { vs: 'http://PowerToysLocalMonaco/monacoSRC/min/vs' } });
|
||||
require(['vs/editor/editor.main'], async function () {
|
||||
await registerAdditionalLanguages(monaco)
|
||||
|
||||
const editor = monaco.editor.create(document.getElementById('container'), {
|
||||
automaticLayout: true,
|
||||
language: 'reg',
|
||||
minimap: { enabled: false },
|
||||
});
|
||||
|
||||
window.onresize = () => {
|
||||
editor.layout();
|
||||
};
|
||||
|
||||
editor.getModel().onDidChangeContent((event) => {
|
||||
window.chrome.webview.postMessage({ 'id': 'contentChanged', 'content': editor.getValue() });
|
||||
});
|
||||
|
||||
editor.focus();
|
||||
|
||||
window.editor = editor;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<UserControl
|
||||
x:Class="RegistryPreviewUILib.MonacoEditorControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:RegistryPreviewUILib"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<tkconverters:BoolToVisibilityConverter
|
||||
x:Key="BoolToInvertedVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<ProgressRing
|
||||
Width="48"
|
||||
Height="48"
|
||||
Visibility="{x:Bind IsLoading, Mode=OneWay}" />
|
||||
<Border
|
||||
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
Visibility="{x:Bind IsLoading, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
||||
<controls:WebView2
|
||||
x:Name="Browser"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Loaded="Browser_Loaded" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Web;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Windows.UI;
|
||||
|
||||
namespace RegistryPreviewUILib
|
||||
{
|
||||
[INotifyPropertyChanged]
|
||||
public sealed partial class MonacoEditorControl : UserControl, IDisposable
|
||||
{
|
||||
private readonly Timer _textChangedThrottle;
|
||||
private bool _textChangedThrottled;
|
||||
|
||||
public string Text { get; private set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
public event EventHandler TextChanged;
|
||||
|
||||
public MonacoEditorControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", MonacoHelper.TempFolderPath, EnvironmentVariableTarget.Process);
|
||||
|
||||
_textChangedThrottle = new Timer(250);
|
||||
_textChangedThrottle.Elapsed += OnTextChangedThrottleElapsed;
|
||||
_textChangedThrottle.AutoReset = false;
|
||||
|
||||
ActualThemeChanged += OnActualThemeChanged;
|
||||
}
|
||||
|
||||
public async Task SetTextAsync(string text)
|
||||
{
|
||||
Text = text;
|
||||
|
||||
if (!IsLoading)
|
||||
{
|
||||
var encodedText = HttpUtility.JavaScriptStringEncode(text);
|
||||
await Browser.CoreWebView2.ExecuteScriptAsync($"editor.setValue('{encodedText}')");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnActualThemeChanged(FrameworkElement sender, object args)
|
||||
{
|
||||
await SetThemeAsync();
|
||||
}
|
||||
|
||||
private async void Browser_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
await Browser.EnsureCoreWebView2Async();
|
||||
Browser.DefaultBackgroundColor = Color.FromArgb(0, 0, 0, 0);
|
||||
Browser.CoreWebView2.NavigationCompleted += CoreWebView2_NavigationCompleted;
|
||||
Browser.CoreWebView2.PermissionRequested += CoreWebView2_PermissionRequested;
|
||||
Browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
|
||||
Browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
|
||||
Browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
|
||||
Browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
|
||||
Browser.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false;
|
||||
Browser.CoreWebView2.Settings.IsScriptEnabled = true;
|
||||
Browser.CoreWebView2.Settings.IsWebMessageEnabled = true;
|
||||
#if DEBUG
|
||||
Browser.CoreWebView2.Settings.AreDevToolsEnabled = true;
|
||||
#else
|
||||
Browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
|
||||
#endif
|
||||
|
||||
Browser.CoreWebView2.SetVirtualHostNameToFolderMapping(
|
||||
MonacoHelper.VirtualHostName,
|
||||
MonacoHelper.MonacoDirectory,
|
||||
CoreWebView2HostResourceAccessKind.Allow);
|
||||
|
||||
var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty;
|
||||
var index = Path.GetFullPath(Path.Combine(assemblyDir, "Assets", "RegistryPreview", "index.html"));
|
||||
Browser.CoreWebView2.Navigate(index);
|
||||
}
|
||||
|
||||
private void CoreWebView2_PermissionRequested(CoreWebView2 sender, CoreWebView2PermissionRequestedEventArgs args)
|
||||
{
|
||||
if (args.PermissionKind == CoreWebView2PermissionKind.ClipboardRead)
|
||||
{
|
||||
// Hide the permission request dialog
|
||||
args.State = CoreWebView2PermissionState.Allow;
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void CoreWebView2_NavigationCompleted(CoreWebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
|
||||
{
|
||||
await SetThemeAsync();
|
||||
IsLoading = false;
|
||||
await SetTextAsync(Text);
|
||||
|
||||
Browser.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived;
|
||||
Browser.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
private void CoreWebView2_WebMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
var json = JsonNode.Parse(args.WebMessageAsJson);
|
||||
if (json == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var id = json["id"];
|
||||
if (id == null || !id.ToString().Equals("contentChanged", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var content = json["content"].ToString();
|
||||
if (content == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Text = content;
|
||||
ThrottleTextChanged();
|
||||
}
|
||||
|
||||
private async Task SetThemeAsync()
|
||||
{
|
||||
var theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? "vs" : "vs-dark";
|
||||
await Browser.CoreWebView2.ExecuteScriptAsync($"monaco.editor.setTheme('{theme}')");
|
||||
}
|
||||
|
||||
private void OnTextChangedThrottleElapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (_textChangedThrottled)
|
||||
{
|
||||
_textChangedThrottled = false;
|
||||
TextChanged?.Invoke(this, EventArgs.Empty);
|
||||
_textChangedThrottle.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrottleTextChanged()
|
||||
{
|
||||
if (_textChangedThrottle.Enabled)
|
||||
{
|
||||
_textChangedThrottled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
TextChanged?.Invoke(this, EventArgs.Empty);
|
||||
_textChangedThrottle.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_textChangedThrottle?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RegistryPreviewUILib
|
||||
{
|
||||
public static class MonacoHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the virtual host
|
||||
/// </summary>
|
||||
public const string VirtualHostName = "PowerToysLocalMonaco";
|
||||
|
||||
public static string TempFolderPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @"AppData\LocalLow\Microsoft\PowerToys\RegistryPreview-Temp");
|
||||
|
||||
private static string _monacoDirectory;
|
||||
|
||||
public static string GetRuntimeMonacoDirectory()
|
||||
{
|
||||
string codeBase = Assembly.GetExecutingAssembly().Location;
|
||||
string path = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(codeBase) ?? string.Empty, "Assets", "Monaco"));
|
||||
if (Path.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're likely in WinUI3Apps directory and need to go back to the base directory.
|
||||
return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(codeBase) ?? string.Empty, "..", "Assets", "Monaco"));
|
||||
}
|
||||
}
|
||||
|
||||
public static string MonacoDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_monacoDirectory))
|
||||
{
|
||||
_monacoDirectory = GetRuntimeMonacoDirectory();
|
||||
}
|
||||
|
||||
return _monacoDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CommunityToolkit.WinUI.UI.Controls;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
@@ -21,6 +21,8 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
public sealed partial class RegistryPreviewMainPage : Page
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
/// <summary>
|
||||
/// Event that is will prevent the app from closing if the "save file" flag is active
|
||||
/// </summary>
|
||||
@@ -40,43 +42,25 @@ namespace RegistryPreviewUILib
|
||||
resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
resourceLoader.GetString("YesNoCancelDialogCloseButtonText"));
|
||||
}
|
||||
|
||||
// Check to see if the textbox's context menu is open
|
||||
if (textBox.ContextFlyout != null && textBox.ContextFlyout.IsOpen)
|
||||
{
|
||||
textBox.ContextFlyout.Hide();
|
||||
|
||||
// if true, the app will not close yet
|
||||
args.Handled = true;
|
||||
|
||||
// HACK: To fix https://github.com/microsoft/PowerToys/issues/28820, wait a bit for the close animation of the flyout to run before closing the application.
|
||||
// This might be called many times if the flyout still hasn't been closed, as Window_Closed will be called again by App.Current.Exit
|
||||
DispatcherQueue.TryEnqueue(async () =>
|
||||
{
|
||||
await Task.Delay(100);
|
||||
Application.Current.Exit();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired after the visual tree has been fully loaded; the app opens the reg file from here so it can show a message box successfully
|
||||
/// </summary>
|
||||
private void GridPreview_Loaded(object sender, RoutedEventArgs e)
|
||||
private async void GridPreview_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// static flag to track whether the Visual Tree is ready - if the main Grid has been loaded, the tree is ready.
|
||||
visualTreeReady = true;
|
||||
|
||||
// Check to see if the REG file was opened and parsed successfully
|
||||
if (OpenRegistryFile(_appFileName) == false)
|
||||
if (await OpenRegistryFile(_appFileName) == false)
|
||||
{
|
||||
if (File.Exists(_appFileName))
|
||||
{
|
||||
// Allow Refresh and Edit to be enabled because a broken Reg file might be fixable
|
||||
UpdateToolBarAndUI(false, true, true);
|
||||
_updateWindowTitleFunction(resourceLoader.GetString("InvalidRegistryFileTitle"));
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -87,10 +71,10 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
else
|
||||
{
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
|
||||
textBox.Focus(FocusState.Programmatic);
|
||||
MonacoEditor.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -153,16 +137,15 @@ namespace RegistryPreviewUILib
|
||||
if (storageFile != null)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
textBox.TextChanged -= TextBox_TextChanged;
|
||||
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
_appFileName = storageFile.Path;
|
||||
UpdateToolBarAndUI(OpenRegistryFile(_appFileName));
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName));
|
||||
|
||||
// disable the Save button as it's a new file
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// Restore the event handler as we're loaded
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +160,7 @@ namespace RegistryPreviewUILib
|
||||
/// <summary>
|
||||
/// Uses a picker to save out a copy of the current reg file
|
||||
/// </summary>
|
||||
private void SaveAsButton_Click(object sender, RoutedEventArgs e)
|
||||
private async void SaveAsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's
|
||||
// called while running as admin
|
||||
@@ -195,24 +178,24 @@ namespace RegistryPreviewUILib
|
||||
|
||||
_appFileName = filename;
|
||||
SaveFile();
|
||||
UpdateToolBarAndUI(OpenRegistryFile(_appFileName));
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the current REG file from storage
|
||||
/// </summary>
|
||||
private void RefreshButton_Click(object sender, RoutedEventArgs e)
|
||||
private async void RefreshButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
textBox.TextChanged -= TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
|
||||
// reload the current Registry file and update the toolbar accordingly.
|
||||
UpdateToolBarAndUI(OpenRegistryFile(_appFileName), true, true);
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName), true, true);
|
||||
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// restore the TextChanged handler
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -364,12 +347,15 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the text in textBox changes, reload treeView and possibly dataGrid and reset the save button
|
||||
/// When the text in editor changes, reload treeView and possibly dataGrid and reset the save button
|
||||
/// </summary>
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
private void MonacoEditor_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshRegistryFile();
|
||||
saveButton.IsEnabled = true;
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
RefreshRegistryFile();
|
||||
saveButton.IsEnabled = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -21,12 +22,14 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
public sealed partial class RegistryPreviewMainPage : Page
|
||||
{
|
||||
private static SemaphoreSlim _dialogSemaphore = new(1);
|
||||
|
||||
public delegate void UpdateWindowTitleFunction(string title);
|
||||
|
||||
/// <summary>
|
||||
/// Method that opens and processes the passed in file name; expected to be an absolute path and a first time open
|
||||
/// </summary>
|
||||
private bool OpenRegistryFile(string filename)
|
||||
private async Task<bool> OpenRegistryFile(string filename)
|
||||
{
|
||||
// clamp to prevent attempts to open a file larger than 10MB
|
||||
try
|
||||
@@ -46,7 +49,7 @@ namespace RegistryPreviewUILib
|
||||
|
||||
// Disable parts of the UI that can cause trouble when loading
|
||||
ChangeCursor(gridPreview, true);
|
||||
textBox.Text = string.Empty;
|
||||
await MonacoEditor.SetTextAsync(string.Empty);
|
||||
|
||||
// clear the treeView and dataGrid no matter what
|
||||
treeView.RootNodes.Clear();
|
||||
@@ -55,7 +58,7 @@ namespace RegistryPreviewUILib
|
||||
// update the current window's title with the current filename
|
||||
_updateWindowTitleFunction(filename);
|
||||
|
||||
// Load in the whole file in one call and plop it all into textBox
|
||||
// Load in the whole file in one call and plop it all into editor
|
||||
FileStream fileStream = null;
|
||||
try
|
||||
{
|
||||
@@ -68,15 +71,15 @@ namespace RegistryPreviewUILib
|
||||
StreamReader streamReader = new StreamReader(fileStream);
|
||||
|
||||
string filenameText = streamReader.ReadToEnd();
|
||||
textBox.Text = filenameText;
|
||||
await MonacoEditor.SetTextAsync(filenameText);
|
||||
streamReader.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// restore TextChanged handler to make for clean UI
|
||||
textBox.TextChanged += TextBox_TextChanged;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
|
||||
// Reset the cursor but leave textBox disabled as no content got loaded
|
||||
// Reset the cursor but leave editor disabled as no content got loaded
|
||||
ChangeCursor(gridPreview, false);
|
||||
return false;
|
||||
}
|
||||
@@ -89,8 +92,8 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
}
|
||||
|
||||
// now that the file is loaded and in textBox, parse the data
|
||||
ParseRegistryFile(textBox.Text);
|
||||
// now that the file is loaded and in editor, parse the data
|
||||
ParseRegistryFile(MonacoEditor.Text);
|
||||
|
||||
// Getting here means that the entire REG file was parsed without incident
|
||||
// so select the root of the tree and celebrate
|
||||
@@ -120,8 +123,8 @@ namespace RegistryPreviewUILib
|
||||
treeView.RootNodes.Clear();
|
||||
ClearTable();
|
||||
|
||||
// the existing text is still in textBox so parse the data again
|
||||
ParseRegistryFile(textBox.Text);
|
||||
// the existing text is still in editor so parse the data again
|
||||
ParseRegistryFile(MonacoEditor.Text);
|
||||
|
||||
// check to see if there was a key in treeView before the refresh happened
|
||||
if (currentNode != null)
|
||||
@@ -164,7 +167,7 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the text that is passed in, which should be the same text that's in textBox
|
||||
/// Parses the text that is passed in, which should be the same text that's in editor
|
||||
/// </summary>
|
||||
private bool ParseRegistryFile(string filenameText)
|
||||
{
|
||||
@@ -181,10 +184,10 @@ namespace RegistryPreviewUILib
|
||||
// As we'll be processing the text one line at a time, this string will be the current line
|
||||
string registryLine;
|
||||
|
||||
// Brute force editing: for textBox to show Cr-Lf corrected, we need to strip out the \n's
|
||||
// Brute force editing: for editor to show Cr-Lf corrected, we need to strip out the \n's
|
||||
filenameText = filenameText.Replace("\r\n", "\r");
|
||||
|
||||
// split apart all of the text in textBox, where one element in the array represents one line
|
||||
// split apart all of the text in editor, where one element in the array represents one line
|
||||
string[] registryLines = filenameText.Split("\r");
|
||||
if (registryLines.Length <= 1)
|
||||
{
|
||||
@@ -655,8 +658,8 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable command bar buttons and textBox.
|
||||
/// Note that writeButton and textBox all update with the same value on purpose
|
||||
/// Enable command bar buttons
|
||||
/// Note that writeButton and editor all update with the same value on purpose
|
||||
/// </summary>
|
||||
private void UpdateToolBarAndUI(bool enableWrite, bool enableRefresh, bool enableEdit)
|
||||
{
|
||||
@@ -776,21 +779,34 @@ namespace RegistryPreviewUILib
|
||||
/// </summary>
|
||||
private async void ShowMessageBox(string title, string content, string closeButtonText)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
if (_dialogSemaphore.CurrentCount == 0)
|
||||
{
|
||||
Title = title,
|
||||
Content = content,
|
||||
CloseButtonText = closeButtonText,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
return;
|
||||
}
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
try
|
||||
{
|
||||
await _dialogSemaphore.WaitAsync();
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = title,
|
||||
Content = content,
|
||||
CloseButtonText = closeButtonText,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dialogSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -894,7 +910,7 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that saves the current file in place, using the current text in textBox.
|
||||
/// Wrapper method that saves the current file in place, using the current text in editor.
|
||||
/// </summary>
|
||||
private void SaveFile()
|
||||
{
|
||||
@@ -914,8 +930,8 @@ namespace RegistryPreviewUILib
|
||||
fileStream = new FileStream(_appFileName, fileStreamOptions);
|
||||
StreamWriter streamWriter = new StreamWriter(fileStream, System.Text.Encoding.Unicode);
|
||||
|
||||
// if we get here, the file is open and writable so dump the whole contents of textBox
|
||||
string filenameText = textBox.Text;
|
||||
// if we get here, the file is open and writable so dump the whole contents of editor
|
||||
string filenameText = MonacoEditor.Text;
|
||||
streamWriter.Write(filenameText);
|
||||
streamWriter.Flush();
|
||||
streamWriter.Close();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:RegistryPreviewUILib"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tk7controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -133,28 +134,12 @@
|
||||
</CommandBar>
|
||||
</Border>
|
||||
|
||||
<TextBox
|
||||
x:Name="textBox"
|
||||
x:Uid="textBox"
|
||||
<local:MonacoEditorControl
|
||||
x:Name="MonacoEditor"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AcceptsReturn="True"
|
||||
CanBeScrollAnchor="False"
|
||||
CornerRadius="{StaticResource OverlayCornerRadius}"
|
||||
FontFamily="Cascadia Mono, Consolas, Courier New"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTabStop="True"
|
||||
IsTextPredictionEnabled="False"
|
||||
PlaceholderText="{Binding PlaceholderText}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Visible"
|
||||
ScrollViewer.IsHorizontalRailEnabled="True"
|
||||
ScrollViewer.IsVerticalRailEnabled="True"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||
TabIndex="0"
|
||||
TextWrapping="NoWrap" />
|
||||
IsTabStop="True" />
|
||||
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Monaco.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
@@ -39,6 +40,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="MonacoEditorControl.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Sizers" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
|
||||
@@ -52,4 +59,10 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="MonacoEditorControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -199,9 +199,6 @@
|
||||
<data name="SuggestFileName" xml:space="preserve">
|
||||
<value>New Registry file</value>
|
||||
</data>
|
||||
<data name="textBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Registry file text will appear here</value>
|
||||
</data>
|
||||
<data name="titleBarText.ApplicationTitle" xml:space="preserve">
|
||||
<value>Registry Preview</value>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user