diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index ff2b6f0af3..a4971bbc9e 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -601,7 +601,7 @@ FILESUBTYPE
FILESYSPATH
filesystem
FILETIME
-FILETYPE
+filetype
FILEVERSION
Filtergraph
Filterkeyboard
diff --git a/src/common/SettingsAPI/settings_helpers.cpp b/src/common/SettingsAPI/settings_helpers.cpp
index f671d5684c..974b2fff6a 100644
--- a/src/common/SettingsAPI/settings_helpers.cpp
+++ b/src/common/SettingsAPI/settings_helpers.cpp
@@ -25,6 +25,22 @@ namespace PTSettingsHelper
return result;
}
+ std::wstring get_local_low_folder_location()
+ {
+ PWSTR local_app_path;
+ winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, NULL, &local_app_path));
+ std::wstring result{ local_app_path };
+ CoTaskMemFree(local_app_path);
+
+ result += L"\\Microsoft\\PowerToys";
+ std::filesystem::path save_path(result);
+ if (!std::filesystem::exists(save_path))
+ {
+ std::filesystem::create_directories(save_path);
+ }
+ return result;
+ }
+
std::wstring get_module_save_folder_location(std::wstring_view powertoy_key)
{
std::wstring result = get_root_save_folder_location();
diff --git a/src/common/SettingsAPI/settings_helpers.h b/src/common/SettingsAPI/settings_helpers.h
index 2c4e3a24af..9e01b3b206 100644
--- a/src/common/SettingsAPI/settings_helpers.h
+++ b/src/common/SettingsAPI/settings_helpers.h
@@ -12,6 +12,7 @@ namespace PTSettingsHelper
std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
std::wstring get_root_save_folder_location();
+ std::wstring get_local_low_folder_location();
void save_module_settings(std::wstring_view powertoy_name, json::JsonObject& settings);
json::JsonObject load_module_settings(std::wstring_view powertoy_name);
diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs
index d46fa018f4..66888a20d7 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs
+++ b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandler.cs
@@ -58,6 +58,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
_disposedValue = true;
+ this.Unload();
}
}
diff --git a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
index d87cf805f5..b420895a4d 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
+++ b/src/modules/previewpane/MonacoPreviewHandler/MonacoPreviewHandlerControl.cs
@@ -5,10 +5,13 @@
using System;
using System.Diagnostics;
using System.Drawing;
+using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
using System.Windows.Forms;
using Common;
+using Microsoft.PowerToys.PreviewHandler.Monaco.Helpers;
using Microsoft.PowerToys.PreviewHandler.Monaco.Properties;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
@@ -43,18 +46,50 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
///
private Label _loading;
+ ///
+ /// Loading progress bar
+ ///
+ private ProgressBar _loadingBar;
+
+ ///
+ /// Grey background
+ ///
+ private Label _loadingBackground;
+
///
/// Name of the virtual host
///
public const string VirtualHostName = "PowerToysLocalMonaco";
+ ///
+ /// HTML code passed to the file
+ ///
+#nullable enable
+ private string? _html;
+#nullable disable
+
+ ///
+ /// Id for monaco language
+ ///
+ private string _vsCodeLangSet;
+
+ ///
+ /// The content of the previewing file in base64
+ ///
+ private string _base64FileCode;
+
[STAThread]
public override void DoPreview(T dataSource)
{
+ Logger.LogTrace();
+
base.DoPreview(dataSource);
+ // Sets background color
+ new Task(SetBackground).Start();
+
// Starts loading screen
- InitializeLoadingScreen();
+ new Task(InitializeLoadingScreen).Start();
// New webview2 element
_webView = new WebView2();
@@ -70,10 +105,14 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
if (fileSize < _settings.MaxFileSize)
{
+ Task initializeIndexFileAndSelectedFileTask = new Task(() => { InitializeIndexFileAndSelectedFile(filePath); });
+ initializeIndexFileAndSelectedFileTask.Start();
+
try
{
InvokeOnControlThread(() =>
{
+ Logger.LogInfo("Create WebView2 environment");
ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
webView2EnvironmentAwaiter = CoreWebView2Environment
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
@@ -81,6 +120,8 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
.ConfigureAwait(true).GetAwaiter();
webView2EnvironmentAwaiter.OnCompleted(() =>
{
+ _loadingBar.Value = 60;
+ this.Update();
InvokeOnControlThread(async () =>
{
try
@@ -91,49 +132,43 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
}
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
- var vsCodeLangSet = FileHandler.GetLanguage(Path.GetExtension(filePath));
- string fileContent;
- using (StreamReader fileReader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
- {
- fileContent = fileReader.ReadToEnd();
- fileReader.Close();
- }
- var base64FileCode = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileContent));
-
- string html;
-
- // prepping index html to load in
- using (StreamReader htmlFileReader = new StreamReader(new FileStream(Settings.AssemblyDirectory + "\\index.html", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
- {
- html = htmlFileReader.ReadToEnd();
- htmlFileReader.Close();
- }
-
- html = html.Replace("[[PT_LANG]]", vsCodeLangSet, StringComparison.InvariantCulture);
- html = html.Replace("[[PT_WRAP]]", _settings.Wrap ? "1" : "0", StringComparison.InvariantCulture);
- html = html.Replace("[[PT_THEME]]", Settings.GetTheme(), StringComparison.InvariantCulture);
- html = html.Replace("[[PT_CODE]]", base64FileCode, StringComparison.InvariantCulture);
- html = html.Replace("[[PT_URL]]", VirtualHostName, StringComparison.InvariantCulture);
+ _loadingBar.Value = 70;
+ this.Update();
// Initialize WebView
try
{
await _webView.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
+
+ // Wait until html is loaded
+ initializeIndexFileAndSelectedFileTask.Wait();
+
_webView.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, Settings.AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
- _webView.NavigateToString(html);
+
+ Logger.LogInfo("Navigates to string of HTML file");
+
+ _webView.NavigateToString(_html);
_webView.NavigationCompleted += WebView2Init;
_webView.Height = this.Height;
_webView.Width = this.Width;
Controls.Add(_webView);
+ _webView.SendToBack();
+ _loadingBar.Value = 100;
+ this.Update();
}
- catch (NullReferenceException)
+ catch (NullReferenceException e)
{
+ Logger.LogError("NullReferenceException catched. Skipping exception.", e);
}
}
- catch (WebView2RuntimeNotFoundException)
+ catch (WebView2RuntimeNotFoundException e)
{
+ Logger.LogWarning("WebView2 was not found:");
+ Logger.LogWarning(e.Message);
Controls.Remove(_loading);
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
// WebView2 not installed message
Label errorMessage = new Label();
@@ -160,6 +195,8 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
InvokeOnControlThread(() =>
{
Controls.Remove(_loading);
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
Label text = new Label();
text.Text = Resources.Exception_Occurred;
text.Text += e.Message;
@@ -168,6 +205,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
text.Width = 500;
text.Height = 10000;
Controls.Add(text);
+ Logger.LogError(e.Message);
});
}
@@ -175,11 +213,15 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
}
else
{
+ Logger.LogInfo("File is too big to display. Showing error message");
InvokeOnControlThread(() =>
{
Controls.Remove(_loading);
+ _loadingBar.Dispose();
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
Label errorMessage = new Label();
- errorMessage.Text = Resources.Max_File_Size_Error;
+ errorMessage.Text = Resources.Max_File_Size_Error.Replace("%1", (_settings.MaxFileSize / 1000).ToString(CultureInfo.CurrentCulture), StringComparison.InvariantCulture);
errorMessage.Width = 500;
errorMessage.Height = 50;
Controls.Add(errorMessage);
@@ -194,6 +236,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
{
_webView.Height = this.Height;
_webView.Width = this.Width;
+ this.Update();
}
///
@@ -205,6 +248,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
// Checks if already navigated
if (!_hasNavigated)
{
+ Logger.LogInfo("Setting WebView2 settings");
CoreWebView2Settings settings = (sender as WebView2).CoreWebView2.Settings;
#if DEBUG
@@ -234,10 +278,17 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
// Disable status bar
settings.IsStatusBarEnabled = false;
+ Logger.LogInfo("Remove loading elements");
Controls.Remove(_loading);
+ Controls.Remove(_loadingBar);
+ Controls.Remove(_loadingBackground);
#if DEBUG
_webView.CoreWebView2.OpenDevToolsWindow();
+ Logger.LogInfo("Opened Dev Tools window, because solution was built in debug mode");
#endif
+
+ _loadingBar.Value = 80;
+ this.Update();
}
}
@@ -251,6 +302,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
if (_hasNavigated)
{
e.Cancel = false;
+ Logger.LogInfo("Stopped navigation from user");
}
// If it has navigated to index.html it stops further navigations
@@ -260,24 +312,86 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
}
}
- private void InitializeLoadingScreen()
+ private void SetBackground()
{
+ Logger.LogTrace();
InvokeOnControlThread(() =>
{
+ this.BackColor = Settings.BackgroundColor;
+ });
+ }
+
+ private void InitializeLoadingScreen()
+ {
+ Logger.LogTrace();
+ InvokeOnControlThread(() =>
+ {
+ _loadingBackground = new Label();
+ _loadingBackground.BackColor = Settings.BackgroundColor;
+ _loadingBackground.Width = this.Width;
+ _loadingBackground.Height = this.Height;
+ Controls.Add(_loadingBackground);
+ _loadingBackground.BringToFront();
+
+ _loadingBar = new ProgressBar();
+ _loadingBar.Width = this.Width - 10;
+ _loadingBar.Location = new Point(5, this.Height / 2);
+ _loadingBar.Maximum = 100;
+ _loadingBar.Value = 10;
+ Controls.Add(_loadingBar);
+
_loading = new Label();
_loading.Text = Resources.Loading_Screen_Message;
_loading.Width = this.Width;
- _loading.Height = this.Height;
+ _loading.Height = 45;
+ _loading.Location = new Point(0, _loadingBar.Location.Y - _loading.Height);
+ _loading.TextAlign = ContentAlignment.TopCenter;
_loading.Font = new Font("MS Sans Serif", 16, FontStyle.Bold);
_loading.ForeColor = Settings.TextColor;
- _loading.BackColor = Settings.BackgroundColor;
Controls.Add(_loading);
+
+ _loading.BringToFront();
+ _loadingBar.BringToFront();
+
+ this.Update();
});
+ Logger.LogInfo("Loading screen initialized");
+ }
+
+ private void InitializeIndexFileAndSelectedFile(string filePath)
+ {
+ Logger.LogInfo("Starting getting monaco language id out of filetype");
+ _vsCodeLangSet = FileHandler.GetLanguage(Path.GetExtension(filePath));
+
+ using (StreamReader fileReader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
+ {
+ Logger.LogInfo("Starting reading requested file");
+ var fileContent = fileReader.ReadToEnd();
+ fileReader.Close();
+ _base64FileCode = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileContent));
+ Logger.LogInfo("Reading requested file ended");
+ }
+
+ // prepping index html to load in
+ using (StreamReader htmlFileReader = new StreamReader(new FileStream(Settings.AssemblyDirectory + "\\index.html", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
+ {
+ Logger.LogInfo("Starting reading HTML source file");
+ _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);
+ _html = _html.Replace("[[PT_THEME]]", Settings.GetTheme(), StringComparison.InvariantCulture);
+ _html = _html.Replace("[[PT_CODE]]", _base64FileCode, StringComparison.InvariantCulture);
+ _html = _html.Replace("[[PT_URL]]", VirtualHostName, StringComparison.InvariantCulture);
}
private async void DownloadLink_Click(object sender, EventArgs e)
{
await Launcher.LaunchUriAsync(new Uri("https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section"));
+ Logger.LogTrace();
}
}
}
diff --git a/src/modules/previewpane/MonacoPreviewHandler/Properties/Resources.resx b/src/modules/previewpane/MonacoPreviewHandler/Properties/Resources.resx
index 0e872dd186..be4a29da68 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/Properties/Resources.resx
+++ b/src/modules/previewpane/MonacoPreviewHandler/Properties/Resources.resx
@@ -118,22 +118,22 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- This file is too big to preview.
-Max file size: 50KB
- Error message which is shown when the file is too big.
+ This file is too big to preview.
+Max file size: %1KB
+ Error message which is shown when the file is too big. %1 gets replaced by a value. Leave KB (means Kilobyte)
- Exception occurred:
+ Exception occurred:
- Will be shown when an exception occurred.
+ Will be shown when an exception occurred.
- Loading...
+ Loading...
- WebView2 not installed or found.
+ WebView2 not installed or found.
- Download WebView2 to display this file.
+ Download WebView2 to display this file.
\ No newline at end of file
diff --git a/src/modules/previewpane/MonacoPreviewHandler/Settings.cs b/src/modules/previewpane/MonacoPreviewHandler/Settings.cs
index 9779f5c40e..218895b5a8 100644
--- a/src/modules/previewpane/MonacoPreviewHandler/Settings.cs
+++ b/src/modules/previewpane/MonacoPreviewHandler/Settings.cs
@@ -53,7 +53,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
{
if (GetTheme() == "dark")
{
- return Color.DimGray;
+ return System.Drawing.ColorTranslator.FromHtml("#1e1e1e");
}
else
{
diff --git a/src/modules/previewpane/MonacoPreviewHandler/helpers/Logger.cs b/src/modules/previewpane/MonacoPreviewHandler/helpers/Logger.cs
new file mode 100644
index 0000000000..b2bad4b8f9
--- /dev/null
+++ b/src/modules/previewpane/MonacoPreviewHandler/helpers/Logger.cs
@@ -0,0 +1,84 @@
+// 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.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.IO.Abstractions;
+using interop;
+
+namespace Microsoft.PowerToys.PreviewHandler.Monaco.Helpers
+{
+ public static class Logger
+ {
+ private static readonly IFileSystem _fileSystem = new FileSystem();
+ private static readonly string ApplicationLogPath = System.Environment.GetEnvironmentVariable("USERPROFILE") + "\\AppData\\LocalLow\\Microsoft\\PowerToys\\logs\\FileExplorer_localLow\\Monaco";
+
+ static Logger()
+ {
+ if (!_fileSystem.Directory.Exists(ApplicationLogPath))
+ {
+ _fileSystem.Directory.CreateDirectory(ApplicationLogPath);
+ }
+
+ // Using InvariantCulture since this is used for a log file name
+ var logFilePath = _fileSystem.Path.Combine(ApplicationLogPath, "Monaco-log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
+
+ Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
+
+ Trace.AutoFlush = true;
+ }
+
+ public static void LogError(string message)
+ {
+ Log(message, "ERROR");
+ }
+
+ public static void LogError(string message, Exception ex)
+ {
+ Log(
+ message + Environment.NewLine +
+ ex?.Message + Environment.NewLine +
+ "Inner exception: " + Environment.NewLine +
+ ex?.InnerException?.Message + Environment.NewLine +
+ "Stack trace: " + Environment.NewLine +
+ ex?.StackTrace,
+ "ERROR");
+ }
+
+ public static void LogWarning(string message)
+ {
+ Log(message, "WARNING");
+ }
+
+ public static void LogInfo(string message)
+ {
+ Log(message, "INFO");
+ }
+
+ private static void Log(string message, string type)
+ {
+ Trace.WriteLine(type + ": " + DateTime.Now.TimeOfDay);
+ Trace.Indent();
+ Trace.WriteLine(GetCallerInfo());
+ Trace.WriteLine(message);
+ Trace.Unindent();
+ }
+
+ public static void LogTrace()
+ {
+ Log(string.Empty, "Trace");
+ }
+
+ private static string GetCallerInfo()
+ {
+ StackTrace stackTrace = new StackTrace();
+
+ var methodName = stackTrace.GetFrame(3)?.GetMethod();
+ var className = methodName?.DeclaringType.Name;
+ return "[Method]: " + methodName?.Name + " [Class]: " + className;
+ }
+ }
+}
diff --git a/tools/BugReportTool/BugReportTool/Main.cpp b/tools/BugReportTool/BugReportTool/Main.cpp
index f36da41be5..91df7f3948 100644
--- a/tools/BugReportTool/BugReportTool/Main.cpp
+++ b/tools/BugReportTool/BugReportTool/Main.cpp
@@ -297,7 +297,10 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
}
auto settingsRootPath = PTSettingsHelper::get_root_save_folder_location();
- settingsRootPath = settingsRootPath + L"\\";
+ settingsRootPath += L"\\";
+
+ auto localLowPath = PTSettingsHelper::get_local_low_folder_location();
+ localLowPath += L"\\logs\\";
const auto tempDir = temp_directory_path();
auto reportDir = temp_directory_path() / "PowerToys\\";
@@ -314,12 +317,24 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
// Remove updates folder contents
DeleteFolder(reportDir / "Updates");
}
+
catch (...)
{
printf("Failed to copy PowerToys folder\n");
return 1;
}
+ try
+ {
+ copy(localLowPath, reportDir, copy_options::recursive);
+ }
+
+ catch (...)
+ {
+ printf("Failed to copy logs saved in LocalLow\n");
+ return 1;
+ }
+
#ifndef _DEBUG
InstallationFolder::ReportStructure(reportDir);
#endif