diff --git a/src/common/FilePreviewCommon/Assets/Monaco/monacoExtraExtensions.txt b/src/common/FilePreviewCommon/Assets/Monaco/monacoExtraExtensions.txt
new file mode 100644
index 000000000000..aa52256aa8b4
--- /dev/null
+++ b/src/common/FilePreviewCommon/Assets/Monaco/monacoExtraExtensions.txt
@@ -0,0 +1,5 @@
+# Extra file extensions to preview with Monaco.
+
+.ahk # AutoHotKey scripts
+.csv # comma-separated values
+.tsv # tab-separated values
diff --git a/src/common/FilePreviewCommon/FilePreviewCommon.csproj b/src/common/FilePreviewCommon/FilePreviewCommon.csproj
index 5849155ca015..f1acd182f790 100644
--- a/src/common/FilePreviewCommon/FilePreviewCommon.csproj
+++ b/src/common/FilePreviewCommon/FilePreviewCommon.csproj
@@ -26,6 +26,9 @@
Always
+
+ Always
+
Always
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs
index 0e1eb5c90f13..69a6efa1ce66 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/ShellPreviewHandlerPreviewer/ShellPreviewHandlerPreviewer.cs
@@ -206,9 +206,14 @@ public void Clear()
}
}
+ public static bool IsExtensionSupported(string extension)
+ {
+ return !string.IsNullOrEmpty(GetPreviewHandlerGuid(extension));
+ }
+
public static bool IsItemSupported(IFileSystemItem item)
{
- return !string.IsNullOrEmpty(GetPreviewHandlerGuid(item.Extension));
+ return IsExtensionSupported(item.Extension);
}
private static string? GetPreviewHandlerGuid(string fileExt)
diff --git a/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/Helpers/MonacoHelper.cs b/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/Helpers/MonacoHelper.cs
index a1ff9d136d59..c4e60460fd45 100644
--- a/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/Helpers/MonacoHelper.cs
+++ b/src/modules/peek/Peek.FilePreviewer/Previewers/WebBrowserPreviewer/Helpers/MonacoHelper.cs
@@ -8,21 +8,28 @@
using System.IO;
using System.Linq;
using System.Text.Json;
+using System.Text.RegularExpressions;
using Common.UI;
using ManagedCommon;
namespace Peek.FilePreviewer.Previewers
{
- public class MonacoHelper
+ public partial class MonacoHelper
{
- public static readonly HashSet SupportedMonacoFileTypes = GetExtensions();
+ public static readonly HashSet SupportedMonacoFileTypes;
+
+ static MonacoHelper()
+ {
+ SupportedMonacoFileTypes = GetExtensions().Union(GetExtraSupportedExtensions()).ToHashSet();
+ }
public static HashSet GetExtensions()
{
- HashSet set = new HashSet();
+ HashSet set = [];
+
try
{
- JsonDocument languageListDocument = Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.GetLanguages();
+ using JsonDocument languageListDocument = Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.GetLanguages();
JsonElement languageList = languageListDocument.RootElement.GetProperty("list");
foreach (JsonElement e in languageList.EnumerateArray())
{
@@ -43,6 +50,39 @@ public static HashSet GetExtensions()
return set;
}
+ ///
+ /// Get the file extensions which are not present in the JSON languages document but which
+ /// may still be previewed by Monaco.
+ ///
+ /// Filters out extensions handled by Shell preview handlers, so Office will still
+ /// handle rendering .csv and others if it is installed.
+ private static IEnumerable GetExtraSupportedExtensions()
+ {
+ try
+ {
+ string path = Path.Combine(
+ Microsoft.PowerToys.FilePreviewCommon.MonacoHelper.GetRuntimeMonacoDirectory(),
+ "monacoExtraExtensions.txt");
+
+ return File.Exists(path) ?
+ File.ReadAllLines(path)
+ .Select(line => ExtensionsFileRegex().Match(line))
+ .Where(match => match.Success &&
+ !ShellPreviewHandlerPreviewer.IsExtensionSupported(match.Groups[1].Value))
+ .Select(match => match.Groups[1].Value) : [];
+ }
+ catch
+ {
+ return [];
+ }
+ }
+
+ ///
+ /// Extracts the extensions from the extra supported extensions file, ignoring comments.
+ ///
+ [GeneratedRegex(@"^\s*(\.\w+)\s*(#.*)?$")]
+ private static partial Regex ExtensionsFileRegex();
+
///
/// Prepares temp html for the previewing
///