Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Monaco faster and refactor code base #32477

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 58 additions & 78 deletions src/common/FilePreviewCommon/Assets/Monaco/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,7 @@
<html>
<head>
<script>
// Set variables

// Get URL parameters:
// `code` contains the code of the file in base64 encoded
// `theme` can be "light" or "dark"
// `lang` is the language of the file
// `wrap` if the editor is wrapping or not

var theme = ("[[PT_THEME]]" == "dark") ? "vs-dark" : "vs";
var lang = "[[PT_LANG]]";
var wrap = ([[PT_WRAP]] == 1) ? true : false;

var base64code = "[[PT_CODE]]";

// Code taken from https://stackoverflow.com/a/30106551/14774889
var code = decodeURIComponent(atob(base64code).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
var editor;
</script>
<!-- Set browser to Edge-->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Expand Down Expand Up @@ -49,69 +32,66 @@

<body oncontextmenu="onContextMenu()">
<!-- Container for the editor -->
<div id="container"></div>
<div style="font-size:xx-large;position: absolute;top: 50%; right: 50%;background-color: transparent;transform: translate(50%,-50%);">...</div>
<div id="container" style="z-index: 100;"></div>
<!-- Script -->
<script src="http://[[PT_URL]]/monacoSRC/min/vs/loader.js"></script>
<script src="http://[[PT_URL]]/monacoSpecialLanguages.js" type="module"></script>
<script type="module">
var editor;
import { registerAdditionalLanguages } from "http://[[PT_URL]]/monacoSpecialLanguages.js"
require.config({ paths: { vs: 'http://[[PT_URL]]/monacoSRC/min/vs' } });
require(['vs/editor/editor.main'], async function () {
await registerAdditionalLanguages(monaco)
// Creates the editor
// For all parameters: https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
editor = monaco.editor.create(document.getElementById('container'), {
value: code, // Sets content of the editor
language: lang, // Sets language fof the code
readOnly: true, // Sets to readonly
theme: theme, // Sets editor theme
minimap: {enabled: false}, // Disables minimap
lineNumbersMinChars: "3", //Width of the line numbers
scrollbar: {
// Deactivate shadows
shadows: false,

// Render scrollbar automatically
vertical: 'auto',
horizontal: 'auto',

},
wordWrap: (wrap?"on":"off") // Word wraps
});
window.onresize = function (){
editor.layout();
};

// Add switch wrap button to context menu
editor.addAction({
id: 'text-wrap',

label: 'Toggle text wrapping',

// A precondition for this action.
precondition: null,

// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
keybindingContext: null,

contextMenuGroupId: 'cutcopypaste',

contextMenuOrder: 100,

// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: function (ed) {
if(wrap){
editor.updateOptions({ wordWrap: "off" })
}else{
editor.updateOptions({ wordWrap: "on" })
<script src="/monacoSRC/min/vs/loader.js"></script>
<script src="/monacoSpecialLanguages.js" type="module"></script>
<script type="module">
import { registerAdditionalLanguages } from "/monacoSpecialLanguages.js";
window.addEventListener("DOMContentLoaded", function () {
require.config({ paths: { vs: '/monacoSRC/min/vs' } });
require(['vs/editor/editor.main'], async function () {
await registerAdditionalLanguages(monaco)
// Creates the editor
// For all parameters: https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
editor = monaco.editor.create(document.getElementById('container'), {
readOnly: true, // Sets to readonly
minimap: {enabled: false}, // Disables minimap
lineNumbersMinChars: "3", //Width of the line numbers
scrollbar: {
// Deactivate shadows
shadows: false,

// Render scrollbar automatically
vertical: 'auto',
horizontal: 'auto',
},
});
window.onresize = function (){
editor.layout();
};

// Code taken from stackoverflow.com/a/30106551/14774889
onContextMenu();
// Add switch wrap button to context menu
editor.addAction({
id: 'text-wrap',

label: 'Toggle text wrapping',

// A precondition for this action.
precondition: null,

// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
keybindingContext: null,

contextMenuGroupId: 'cutcopypaste',

contextMenuOrder: 100,

// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: function (ed) {
if(wrap){
editor.updateOptions({ wordWrap: "off" })
}else{
editor.updateOptions({ wordWrap: "on" })
}
wrap = !wrap;
}
wrap = !wrap;
}
});
});

onContextMenu();
});

function onContextMenu(){
Expand Down
13 changes: 0 additions & 13 deletions src/common/FilePreviewCommon/MonacoHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,5 @@ public static string GetLanguage(string fileExtension)
return "plaintext";
}
}

public static string ReadIndexHtml()
{
string html;

using (StreamReader htmlFileReader = new StreamReader(new FileStream(MonacoDirectory + "\\index.html", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
html = htmlFileReader.ReadToEnd();
htmlFileReader.Close();
}

return html;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.UI;
Expand Down Expand Up @@ -53,6 +54,8 @@ public Uri? Source
typeof(BrowserControl),
new PropertyMetadata(null, new PropertyChangedCallback((d, e) => ((BrowserControl)d).OnIsDevFilePreviewChanged())));

public Queue<string> JavascriptCommandQueue { get; set; } = [];

// Will actually be true for Markdown files as well.
public bool IsDevFilePreview
{
Expand All @@ -71,6 +74,16 @@ public BrowserControl()
{
this.InitializeComponent();
Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", TempFolderPath.Path, EnvironmentVariableTarget.Process);

PreviewBrowser.NavigationCompleted += async (sender, _) =>
{
foreach (string command in JavascriptCommandQueue)
{
await sender.ExecuteScriptAsync(command);
}

JavascriptCommandQueue.Clear();
};
}

public void Dispose()
Expand Down
16 changes: 15 additions & 1 deletion src/modules/peek/Peek.FilePreviewer/FilePreview.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -107,6 +108,8 @@ private async void Previewer_PropertyChanged(object? sender, System.ComponentMod

public IUnsupportedFilePreviewer? UnsupportedFilePreviewer => Previewer as IUnsupportedFilePreviewer;

public Queue<string> JavascriptCommandQueue { get; set; } = [];

public IFileSystemItem Item
{
get => (IFileSystemItem)GetValue(ItemProperty);
Expand Down Expand Up @@ -180,6 +183,9 @@ private async Task OnItemPropertyChanged()
imagePreviewer.ScalingFactor = ScalingFactor;
}

BrowserPreview.JavascriptCommandQueue.Clear();
JavascriptCommandQueue.Clear();

await UpdatePreviewAsync(_cancellationTokenSource.Token);
}

Expand Down Expand Up @@ -209,6 +215,12 @@ private async Task UpdatePreviewAsync(CancellationToken cancellationToken)
cancellationToken.ThrowIfCancellationRequested();
await Previewer.LoadPreviewAsync(cancellationToken);

if (Previewer is IBrowserPreviewer browserPreviewer)
{
BrowserPreview.JavascriptCommandQueue = browserPreviewer.JavascriptCommandQueue;
JavascriptCommandQueue = browserPreviewer.JavascriptCommandQueue;
}

cancellationToken.ThrowIfCancellationRequested();
await UpdateTooltipAsync(cancellationToken);
}
Expand Down Expand Up @@ -250,6 +262,8 @@ partial void OnPreviewerChanging(IPreviewer? value)
{
value.PropertyChanged += Previewer_PropertyChanged;
}

JavascriptCommandQueue.Clear();
}

private void BrowserPreview_DOMContentLoaded(Microsoft.Web.WebView2.Core.CoreWebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2DOMContentLoadedEventArgs args)
Expand Down Expand Up @@ -349,7 +363,7 @@ private async Task UpdateTooltipAsync(CancellationToken cancellationToken)
sb.Append(fileNameFormatted);

cancellationToken.ThrowIfCancellationRequested();
string fileType = await Task.Run(Item.GetContentTypeAsync);
string fileType = await Item.GetContentTypeAsync().ConfigureAwait(true);
string fileTypeFormatted = string.IsNullOrEmpty(fileType) ? string.Empty : "\n" + ReadableStringHelper.FormatResourceString("PreviewTooltip_FileType", fileType);
sb.Append(fileTypeFormatted);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;

namespace Peek.FilePreviewer.Previewers.Interfaces
{
Expand All @@ -11,5 +12,7 @@ public interface IBrowserPreviewer : IPreviewer, IPreviewTarget
public Uri? Preview { get; }

public bool IsDevFilePreview { get; }

public Queue<string> JavascriptCommandQueue { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ public static HashSet<string> GetExtensions()
/// <summary>
/// Prepares temp html for the previewing
/// </summary>
public static string PreviewTempFile(string fileText, string extension, string tempFolder, bool tryFormat, bool wrapText)
public static (Uri Uri, string VsCodeLangSet, string FileContent) PreviewTempFile(string fileText, string extension, bool tryFormat)
{
// TODO: check if file is too big, add MaxFileSize to settings
return InitializeIndexFileAndSelectedFile(fileText, extension, tempFolder, tryFormat, wrapText);
return InitializeIndexFileAndSelectedFile(fileText, extension, tryFormat);
}

private static string InitializeIndexFileAndSelectedFile(string fileContent, string extension, string tempFolder, bool tryFormat, bool wrapText)
private static (Uri Uri, string VsCodeLangSet, string FileContent) InitializeIndexFileAndSelectedFile(string fileContent, string extension, bool tryFormat)
{
string vsCodeLangSet = Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.GetLanguage(extension);

Expand All @@ -71,21 +71,7 @@ private static string InitializeIndexFileAndSelectedFile(string fileContent, str
}
}

string base64FileCode = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileContent));
string theme = ThemeManager.GetWindowsBaseColor().ToLowerInvariant();

// prepping index html to load in
string html = Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.ReadIndexHtml();

html = html.Replace("[[PT_LANG]]", vsCodeLangSet, StringComparison.InvariantCulture);
html = html.Replace("[[PT_WRAP]]", wrapText ? "1" : "0", StringComparison.InvariantCulture);
html = html.Replace("[[PT_THEME]]", theme, StringComparison.InvariantCulture);
html = html.Replace("[[PT_CODE]]", base64FileCode, StringComparison.InvariantCulture);
html = html.Replace("[[PT_URL]]", Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.VirtualHostName, StringComparison.InvariantCulture);

string filename = tempFolder + "\\" + Guid.NewGuid().ToString() + ".html";
File.WriteAllText(filename, html);
return filename;
return (new Uri("http://" + Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.VirtualHostName + "/index.html"), vsCodeLangSet, fileContent);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Common.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Dispatching;
using Peek.Common.Constants;
Expand Down Expand Up @@ -80,6 +81,21 @@ protected virtual async void Dispose(bool disposing)

private Task<bool>? DisplayInfoTask { get; set; }

private Queue<string> _javascriptCommandQueue = [];

Queue<string> IBrowserPreviewer.JavascriptCommandQueue
{
get
{
return _javascriptCommandQueue;
}

set
{
_javascriptCommandQueue = value;
}
}

public Task<PreviewSize> GetPreviewSizeAsync(CancellationToken cancellationToken)
{
return Task.FromResult(new PreviewSize { MonitorSize = null });
Expand Down Expand Up @@ -111,8 +127,12 @@ await Dispatcher.RunOnUiThread(async () =>

if (IsDevFilePreview && !isHtml && !isMarkdown)
{
var raw = await ReadHelper.Read(File.Path.ToString());
Preview = new Uri(MonacoHelper.PreviewTempFile(raw, File.Extension, TempFolderPath.Path, _previewSettings.SourceCodeTryFormat, _previewSettings.SourceCodeWrapText));
string raw = await Task.Run(() => ReadHelper.Read(File.Path.ToString()));
(Preview, string vsCodeLangSet, string fileContent) = MonacoHelper.PreviewTempFile(raw, File.Extension, _previewSettings.SourceCodeTryFormat);
_javascriptCommandQueue.Enqueue("editor.setValue(\"" + fileContent.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "\\r") + "\");");
_javascriptCommandQueue.Enqueue("monaco.editor.setModelLanguage(editor.getModel(), \"" + vsCodeLangSet + "\");");
_javascriptCommandQueue.Enqueue("editor.updateOptions({\"wordWrap\": \"" + (_previewSettings.SourceCodeWrapText ? "on" : "off") + "\"});");
_javascriptCommandQueue.Enqueue("editor.updateOptions({\"theme\": \"" + (ThemeManager.GetWindowsBaseColor().Equals("dark", StringComparison.OrdinalIgnoreCase) ? "vs-dark" : "vs") + "\"});");
}
else if (isMarkdown)
{
Expand Down
Loading
Loading