Rename the [Ee]xts dir to ext (#38852)

**WARNING:** This PR will probably blow up all in-flight PRs

at some point in the early days of CmdPal, two of us created seperate
`Exts` and `exts` dirs. Depending on what the casing was on the branch
that you checked one of those out from, it'd get stuck like that on your
PC forever.

Windows didn't care, so we never noticed.

But GitHub does care, and now browsing the source on GitHub is basically
impossible.

Closes #38081
This commit is contained in:
Mike Griese
2025-04-15 06:07:22 -05:00
committed by GitHub
parent 60f50d853b
commit 2b5181b4c9
379 changed files with 35 additions and 35 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,49 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 4.665C0 4.29773 0.297731 4 0.665 4H3.32533C3.6926 4 3.99033 4.29773 3.99033 4.665V7.99999H0V4.665Z" fill="url(#paint0_linear_1875_18082)"/>
<path d="M5.11801 3.59869C4.86245 3.33492 4.8686 2.9134 5.13175 2.65721L7.04127 0.798149C7.30442 0.54195 7.72492 0.548088 7.98048 0.811859L9.83511 2.72606C10.0907 2.98983 10.0845 3.41135 9.82137 3.66755L7.91186 5.5266C7.64871 5.7828 7.22821 5.77667 6.97264 5.51289L5.11801 3.59869Z" fill="url(#paint1_linear_1875_18082)"/>
<path d="M11.3248 6.96737C11.4366 6.61756 11.8108 6.42509 12.1604 6.53747L14.694 7.35177C15.0437 7.46415 15.2364 7.83883 15.1245 8.18864L14.3114 10.7309C14.1995 11.0807 13.8254 11.2731 13.4757 11.1608L10.9421 10.3465C10.5925 10.2341 10.3997 9.85939 10.5116 9.50958L11.3248 6.96737Z" fill="url(#paint2_linear_1875_18082)"/>
<path d="M11.1783 1.8671C11.0653 1.51765 11.2568 1.14234 11.6061 1.02882L14.137 0.206196C14.4863 0.0926694 14.861 0.283918 14.9741 0.633361L15.7955 3.17288C15.9085 3.52233 15.717 3.89764 15.3677 4.01116L12.8368 4.83379C12.4875 4.94731 12.1128 4.75606 11.9997 4.40662L11.1783 1.8671Z" fill="url(#paint3_linear_1875_18082)"/>
<path d="M0 8H3.99033V12H0V8Z" fill="url(#paint4_linear_1875_18082)"/>
<path d="M3.99023 8H7.31556C7.68283 8 7.98056 8.29773 7.98056 8.665V12H3.99023V8Z" fill="url(#paint5_linear_1875_18082)"/>
<path d="M0 12H3.99033V16H0.664999C0.29773 16 0 15.7023 0 15.335V12Z" fill="url(#paint6_linear_1875_18082)"/>
<path d="M3.99023 12H7.98056V16H3.99023V12Z" fill="url(#paint7_linear_1875_18082)"/>
<path d="M7.98047 12H11.3058C11.6731 12 11.9708 12.2977 11.9708 12.665V15.335C11.9708 15.7023 11.6731 16 11.3058 16H7.98047V12Z" fill="url(#paint8_linear_1875_18082)"/>
<defs>
<linearGradient id="paint0_linear_1875_18082" x1="-0.0906894" y1="3.72727" x2="4.54629" y2="8.62516" gradientUnits="userSpaceOnUse">
<stop stop-color="#26AEE9"/>
<stop offset="1" stop-color="#1EA1E4"/>
</linearGradient>
<linearGradient id="paint1_linear_1875_18082" x1="4.75107" y1="1.09701" x2="9.25021" y2="5.25282" gradientUnits="userSpaceOnUse">
<stop offset="0.0339518" stop-color="#0B589A"/>
<stop offset="1" stop-color="#14518A"/>
</linearGradient>
<linearGradient id="paint2_linear_1875_18082" x1="11.5241" y1="6.04652" x2="14.4446" y2="12.1313" gradientUnits="userSpaceOnUse">
<stop stop-color="#24ACE8"/>
<stop offset="1" stop-color="#1FA3E4"/>
</linearGradient>
<linearGradient id="paint3_linear_1875_18082" x1="10.8034" y1="1.00298" x2="15.638" y2="4.8226" gradientUnits="userSpaceOnUse">
<stop stop-color="#1694DA"/>
<stop offset="1" stop-color="#0067B2"/>
</linearGradient>
<linearGradient id="paint4_linear_1875_18082" x1="-0.0906894" y1="7.72727" x2="4.54629" y2="12.6252" gradientUnits="userSpaceOnUse">
<stop stop-color="#1997DB"/>
<stop offset="1" stop-color="#027BD5"/>
</linearGradient>
<linearGradient id="paint5_linear_1875_18082" x1="3.89954" y1="7.72727" x2="8.53652" y2="12.6252" gradientUnits="userSpaceOnUse">
<stop stop-color="#1EA2E3"/>
<stop offset="1" stop-color="#1790CB"/>
</linearGradient>
<linearGradient id="paint6_linear_1875_18082" x1="-0.0906894" y1="11.7273" x2="4.54629" y2="16.6252" gradientUnits="userSpaceOnUse">
<stop stop-color="#0B599C"/>
<stop offset="1" stop-color="#175086"/>
</linearGradient>
<linearGradient id="paint7_linear_1875_18082" x1="3.89954" y1="11.7273" x2="8.53652" y2="16.6252" gradientUnits="userSpaceOnUse">
<stop stop-color="#057FD5"/>
<stop offset="1" stop-color="#0063AC"/>
</linearGradient>
<linearGradient id="paint8_linear_1875_18082" x1="7.88978" y1="11.7273" x2="12.5268" y2="16.6252" gradientUnits="userSpaceOnUse">
<stop stop-color="#1892CF"/>
<stop offset="1" stop-color="#0071C5"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1,116 @@
// 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 Microsoft.CmdPal.Ext.Registry.Helpers;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.Registry.Classes;
/// <summary>
/// A entry of the registry.
/// </summary>
internal sealed class RegistryEntry
{
#pragma warning disable CS8632
/// <summary>
/// Gets the full path to a registry key.
/// </summary>
internal string KeyPath { get; }
/// <summary>
/// Gets the registry key for this entry.
/// </summary>
internal RegistryKey? Key { get; }
/// <summary>
/// Gets a possible exception that was occurred when try to open this registry key (e.g. <see cref="UnauthorizedAccessException"/>).
/// </summary>
internal Exception? Exception { get; }
/// <summary>
/// Gets the name of the current selected registry value.
/// </summary>
internal string? ValueName { get; }
/// <summary>
/// Gets the value of the current selected registry value.
/// </summary>
internal object? ValueData { get; }
#pragma warning restore CS8632
/// <summary>
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
/// </summary>
/// <param name="keyPath">The full path to the registry key for this entry.</param>
/// <param name="exception">A exception that was occurred when try to access this registry key.</param>
internal RegistryEntry(string keyPath, Exception exception)
{
KeyPath = keyPath;
Exception = exception;
}
/// <summary>
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> for this entry.</param>
internal RegistryEntry(RegistryKey key)
{
KeyPath = key.Name;
Key = key;
}
/// <summary>
/// Initializes a new instance of the <see cref="RegistryEntry"/> class.
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> for this entry.</param>
/// <param name="valueName">The value name of the current selected registry value.</param>
/// <param name="value">The value of the current selected registry value.</param>
internal RegistryEntry(RegistryKey key, string valueName, object value)
{
KeyPath = key.Name;
Key = key;
ValueName = valueName;
ValueData = value;
}
/// <summary>
/// Return the registry key.
/// </summary>
/// <returns>A registry key.</returns>
internal string GetRegistryKey()
{
return $"{Key?.Name ?? KeyPath}";
}
/// <summary>
/// Return the value name with the complete registry key.
/// </summary>
/// <returns>A value name with the complete registry key.</returns>
internal string GetValueNameWithKey()
{
return $"{Key?.Name ?? KeyPath}\\\\{ValueName?.ToString() ?? string.Empty}";
}
/// <summary>
/// Return the value data of a value name inside a registry key.
/// </summary>
/// <returns>A value data.</returns>
internal string GetValueData()
{
if (Key is null)
{
return KeyPath;
}
if (string.IsNullOrEmpty(ValueName))
{
return Key.Name;
}
return ValueHelper.GetValue(Key, ValueName);
}
}

View File

@@ -0,0 +1,49 @@
// 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 Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI;
namespace Microsoft.CmdPal.Ext.Registry.Commands;
internal sealed partial class CopyRegistryInfoCommand : InvokableCommand
{
private readonly RegistryEntry _entry;
private readonly string _stringToCopy;
internal CopyRegistryInfoCommand(RegistryEntry entry, CopyType typeToCopy)
{
if (typeToCopy == CopyType.Key)
{
Name = Resources.CopyKeyNamePath;
Icon = new IconInfo("\xE8C8"); // Copy Icon
_stringToCopy = entry.GetRegistryKey();
}
else if (typeToCopy == CopyType.ValueData)
{
Name = Resources.CopyValueData;
Icon = new IconInfo("\xF413"); // CopyTo Icon
_stringToCopy = entry.GetValueData();
}
else if (typeToCopy == CopyType.ValueName)
{
Name = Resources.CopyValueName;
Icon = new IconInfo("\xE8C8"); // Copy Icon
_stringToCopy = entry.GetValueNameWithKey();
}
_entry = entry;
}
public override CommandResult Invoke()
{
ClipboardHelper.SetText(_stringToCopy);
return CommandResult.Dismiss();
}
}

View File

@@ -0,0 +1,66 @@
// 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Helpers;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI;
namespace Microsoft.CmdPal.Ext.Registry.Commands;
internal sealed partial class OpenKeyInEditorCommand : InvokableCommand
{
private readonly RegistryEntry _entry;
internal OpenKeyInEditorCommand(RegistryEntry entry)
{
Name = Resources.OpenKeyInRegistryEditor;
Icon = new IconInfo("\xE8A7"); // OpenInNewWindow icon
_entry = entry;
}
internal static bool TryToOpenInRegistryEditor(in RegistryEntry entry)
{
try
{
RegistryHelper.OpenRegistryKey(entry.Key?.Name ?? entry.KeyPath);
return true;
}
catch (System.ComponentModel.Win32Exception)
{
// TODO GH #118 We need a convenient way to show errors to a user
// MessageBox.Show(
// Resources.OpenInRegistryEditorAccessExceptionText,
// Resources.OpenInRegistryEditorAccessExceptionTitle,
// MessageBoxButton.OK,
// MessageBoxImage.Error);
return false;
}
#pragma warning disable CS0168, IDE0059
catch (Exception exception)
{
// TODO GH #108: Logging
// Log.Exception("Error on opening Windows registry editor", exception, typeof(Main));
return false;
}
#pragma warning restore CS0168, IDE0059
}
public override CommandResult Invoke()
{
TryToOpenInRegistryEditor(_entry);
return CommandResult.KeepOpen();
}
}

View File

@@ -0,0 +1,51 @@
// 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.CmdPal.Ext.Registry.Constants;
/// <summary>
/// This class contains names for important registry keys
/// </summary>
internal static class KeyName
{
/// <summary>
/// The first name part of each base key without the underscore
/// </summary>
internal const string FirstPart = "HKEY";
/// <summary>
/// The first name part of each base key follow by a underscore
/// </summary>
internal const string FirstPartUnderscore = "HKEY_";
/// <summary>
/// The short name for the base key HKEY_CLASSES_ROOT (see <see cref="Win32.Registry.ClassesRoot"/>)
/// </summary>
internal const string ClassRootShort = "HKCR";
/// <summary>
/// The short name for the base key HKEY_CURRENT_CONFIG (see <see cref="Win32.Registry.CurrentConfig"/>)
/// </summary>
internal const string CurrentConfigShort = "HKCC";
/// <summary>
/// The short name for the base key HKEY_CURRENT_USER (see <see cref="Win32.Registry.CurrentUser"/>)
/// </summary>
internal const string CurrentUserShort = "HKCU";
/// <summary>
/// The short name for the base key HKEY_LOCAL_MACHINE (see <see cref="Win32.Registry.LocalMachine"/>)
/// </summary>
internal const string LocalMachineShort = "HKLM";
/// <summary>
/// The short name for the base key HKEY_PERFORMANCE_DATA (see <see cref="Win32.Registry.PerformanceData"/>)
/// </summary>
internal const string PerformanceDataShort = "HKPD";
/// <summary>
/// The short name for the base key HKEY_USERS (see <see cref="Win32.Registry.Users"/>)
/// </summary>
internal const string UsersShort = "HKU";
}

View File

@@ -0,0 +1,31 @@
// 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.CmdPal.Ext.Registry.Constants;
/// <summary>
/// This class contain all maximum text length.
/// </summary>
public static class MaxTextLength
{
/// <summary>
/// The maximum length for the title text length with two context menu symbols on the right.
/// </summary>
internal const int MaximumTitleLengthWithTwoSymbols = 44;
/// <summary>
/// The maximum length for the title text length with three context menu symbols on the right.
/// </summary>
internal const int MaximumTitleLengthWithThreeSymbols = 40;
/// <summary>
/// The maximum length for the sub-title text length with two context menu symbols on the right.
/// </summary>
internal const int MaximumSubTitleLengthWithTwoSymbols = 85;
/// <summary>
/// The maximum length for the sub-title text length with three context menu symbols on the right.
/// </summary>
internal const int MaximumSubTitleLengthWithThreeSymbols = 78;
}

View File

@@ -0,0 +1,12 @@
// 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.CmdPal.Ext.Registry;
public enum CopyType
{
Key,
ValueData,
ValueName,
}

View File

@@ -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.CmdPal.Ext.Registry.Enumerations;
/// <summary>
/// The truncate side for a to long text
/// </summary>
internal enum TruncateSide
{
/// <summary>
/// Truncate a text only from the right side
/// </summary>
OnlyFromLeft,
/// <summary>
/// Truncate a text only from the left side
/// </summary>
OnlyFromRight,
}

View File

@@ -0,0 +1,42 @@
// 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.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Commands;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.Registry.Helpers;
/// <summary>
/// Helper class to easier work with context menu entries
/// </summary>
internal static class ContextMenuHelper
{
/// <summary>
/// Return a list with all context menu entries for the given <see cref="Result"/>
/// <para>Symbols taken from <see href="https://learn.microsoft.com/windows/uwp/design/style/segoe-ui-symbol-font"/></para>
/// </summary>
internal static List<CommandContextItem> GetContextMenu(RegistryEntry entry)
{
var list = new List<CommandContextItem>();
if (string.IsNullOrEmpty(entry.ValueName))
{
list.Add(new CommandContextItem(new CopyRegistryInfoCommand(entry, CopyType.Key)));
}
else
{
list.Add(new CommandContextItem(new CopyRegistryInfoCommand(entry, CopyType.ValueData)));
list.Add(new CommandContextItem(new CopyRegistryInfoCommand(entry, CopyType.ValueName)));
}
// list.Add(new CommandContextItem(new OpenKeyInEditorCommand(entry)));
return list;
}
}

View File

@@ -0,0 +1,116 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CmdPal.Ext.Registry.Constants;
namespace Microsoft.CmdPal.Ext.Registry.Helpers;
/// <summary>
/// Helper class to easier work with queries
/// </summary>
internal static partial class QueryHelper
{
/// <summary>
/// The character to distinguish if the search query contain multiple parts (typically "\\")
/// </summary>
internal const string QuerySplitCharacter = "\\\\";
/// <summary>
/// A list that contain short names of all registry base keys
/// </summary>
private static readonly IReadOnlyDictionary<string, string> _shortBaseKeys = new Dictionary<string, string>(6)
{
{ Win32.Registry.ClassesRoot.Name, KeyName.ClassRootShort },
{ Win32.Registry.CurrentConfig.Name, KeyName.CurrentConfigShort },
{ Win32.Registry.CurrentUser.Name, KeyName.CurrentUserShort },
{ Win32.Registry.LocalMachine.Name, KeyName.LocalMachineShort },
{ Win32.Registry.PerformanceData.Name, KeyName.PerformanceDataShort },
{ Win32.Registry.Users.Name, KeyName.UsersShort },
};
[GeneratedRegex(@"/(?<=^(?:[^""]*""[^""]*"")*[^""]*)(?<!//.+)", RegexOptions.IgnoreCase, "en-US")]
private static partial Regex FrontToBackSlashRegex();
/// <summary>
/// Sanitize the query to avoid issues with the regex
/// </summary>
/// <param name="query">Query containing front-slash</param>
/// <returns>A string replacing all the front-slashes with back-slashes</returns>
private static string SanitizeQuery(in string query)
{
var sanitizedQuery = FrontToBackSlashRegex().Replace(query, "\\");
return sanitizedQuery.Replace("\"", string.Empty);
}
/// <summary>
/// Return the parts of a given query
/// </summary>
/// <param name="query">The query that could contain parts</param>
/// <param name="queryKey">The key part of the query</param>
/// <param name="queryValueName">The value name part of the query</param>
/// <returns><see langword="true"/> when the query search for a key and a value name, otherwise <see langword="false"/></returns>
internal static bool GetQueryParts(in string query, out string queryKey, out string queryValueName)
{
var sanitizedQuery = SanitizeQuery(query);
if (!sanitizedQuery.Contains(QuerySplitCharacter, StringComparison.InvariantCultureIgnoreCase))
{
queryKey = sanitizedQuery;
queryValueName = string.Empty;
return false;
}
var querySplit = sanitizedQuery.Split(QuerySplitCharacter);
queryKey = querySplit.First();
queryValueName = querySplit.Last();
return true;
}
/// <summary>
/// Return a registry key with a long base key
/// </summary>
/// <param name="registryKey">A registry key with a short base key</param>
/// <returns>A registry key with a long base key</returns>
internal static string GetKeyWithLongBaseKey(in string registryKey)
{
foreach (var shortName in _shortBaseKeys)
{
if (!registryKey.StartsWith(shortName.Value, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
return registryKey.Replace(shortName.Value, shortName.Key, StringComparison.InvariantCultureIgnoreCase);
}
return registryKey;
}
/// <summary>
/// Return a registry key with a short base key (useful to reduce the text length of a registry key)
/// </summary>
/// <param name="registryKey">A registry key with a full base key</param>
/// <returns>A registry key with a short base key</returns>
internal static string GetKeyWithShortBaseKey(in string registryKey)
{
foreach (var shortName in _shortBaseKeys)
{
if (!registryKey.StartsWith(shortName.Key, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
return registryKey.Replace(shortName.Key, shortName.Value, StringComparison.InvariantCultureIgnoreCase);
}
return registryKey;
}
}

View File

@@ -0,0 +1,245 @@
// 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.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Constants;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.Registry.Helpers;
/// <summary>
/// Helper class to easier work with the registry
/// </summary>
internal static class RegistryHelper
{
/// <summary>
/// A list that contain all registry base keys in a long/full version and in a short version (e.g HKLM = HKEY_LOCAL_MACHINE)
/// </summary>
private static readonly IReadOnlyDictionary<string, RegistryKey> _baseKeys = new Dictionary<string, RegistryKey>(12)
{
{ KeyName.ClassRootShort, Win32.Registry.ClassesRoot },
{ Win32.Registry.ClassesRoot.Name, Win32.Registry.ClassesRoot },
{ KeyName.CurrentConfigShort, Win32.Registry.CurrentConfig },
{ Win32.Registry.CurrentConfig.Name, Win32.Registry.CurrentConfig },
{ KeyName.CurrentUserShort, Win32.Registry.CurrentUser },
{ Win32.Registry.CurrentUser.Name, Win32.Registry.CurrentUser },
{ KeyName.LocalMachineShort, Win32.Registry.LocalMachine },
{ Win32.Registry.LocalMachine.Name, Win32.Registry.LocalMachine },
{ KeyName.PerformanceDataShort, Win32.Registry.PerformanceData },
{ Win32.Registry.PerformanceData.Name, Win32.Registry.PerformanceData },
{ KeyName.UsersShort, Win32.Registry.Users },
{ Win32.Registry.Users.Name, Win32.Registry.Users },
};
/// <summary>
/// Try to find registry base keys based on the given query
/// </summary>
/// <param name="query">The query to search</param>
/// <returns>A combination of a list of base <see cref="RegistryKey"/> and the sub keys</returns>
#pragma warning disable CS8632
internal static (IEnumerable<RegistryKey>? BaseKey, string SubKey) GetRegistryBaseKey(in string query)
{
if (string.IsNullOrWhiteSpace(query))
{
return (null, string.Empty);
}
var baseKey = query.Split('\\').FirstOrDefault() ?? string.Empty;
var subKey = string.Empty;
if (!string.IsNullOrEmpty(baseKey))
{
subKey = query.Replace(baseKey, string.Empty, StringComparison.InvariantCultureIgnoreCase).TrimStart('\\');
}
var baseKeyResult = _baseKeys
.Where(found => found.Key.StartsWith(baseKey, StringComparison.InvariantCultureIgnoreCase))
.Select(found => found.Value)
.Distinct();
return (baseKeyResult, subKey);
}
/// <summary>
/// Return a list of all registry base key
/// </summary>
/// <returns>A list with all registry base keys</returns>
internal static ICollection<RegistryEntry> GetAllBaseKeys()
{
return new Collection<RegistryEntry>
{
new(Win32.Registry.ClassesRoot),
new(Win32.Registry.CurrentConfig),
new(Win32.Registry.CurrentUser),
new(Win32.Registry.LocalMachine),
new(Win32.Registry.PerformanceData),
new(Win32.Registry.Users),
};
}
/// <summary>
/// Search for the given sub-key path in the given registry base key
/// </summary>
/// <param name="baseKey">The base <see cref="RegistryKey"/></param>
/// <param name="subKeyPath">The path of the registry sub-key</param>
/// <returns>A list with all found registry keys</returns>
internal static ICollection<RegistryEntry> SearchForSubKey(in RegistryKey baseKey, in string subKeyPath)
{
if (string.IsNullOrEmpty(subKeyPath))
{
return FindSubKey(baseKey, string.Empty);
}
var subKeysNames = subKeyPath.Split('\\');
var index = 0;
RegistryKey? subKey = baseKey;
#pragma warning restore CS8632
ICollection<RegistryEntry> result;
do
{
result = FindSubKey(subKey, subKeysNames.ElementAtOrDefault(index) ?? string.Empty);
if (result.Count == 0)
{
// If a subKey can't be found, show no results.
break;
}
if (result.Count == 1 && index < subKeysNames.Length)
{
subKey = result.First().Key;
}
if (result.Count > 1 || subKey == null)
{
break;
}
index++;
}
while (index < subKeysNames.Length);
return result;
}
/// <summary>
/// Return a human readable summary of a given <see cref="RegistryKey"/>
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> for the summary</param>
/// <returns>A human readable summary</returns>
internal static string GetSummary(in RegistryKey key)
{
return $"{Resources.SubKeys} {key.SubKeyCount} - {Resources.Values} {key.ValueCount}";
}
/// <summary>
/// Open a given registry key in the registry editor
/// </summary>
/// <param name="fullKey">The registry key to open</param>
internal static void OpenRegistryKey(in string fullKey)
{
// Set the registry key
Win32.Registry.SetValue(@"HKEY_Current_User\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", "LastKey", fullKey);
// Open regedit.exe with multi-instance option
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "regedit.exe",
Arguments = "-m",
UseShellExecute = true,
Verb = "runas", // Runs as Administrator
};
Process.Start(startInfo);
}
/// <summary>
/// Try to find the given registry sub-key in the given registry parent-key
/// </summary>
/// <param name="parentKey">The parent-key, also the root to start the search</param>
/// <param name="searchSubKey">The sub-key to find</param>
/// <returns>A list with all found registry sub-keys</returns>
private static Collection<RegistryEntry> FindSubKey(in RegistryKey parentKey, in string searchSubKey)
{
var list = new Collection<RegistryEntry>();
try
{
foreach (var subKey in parentKey.GetSubKeyNames().OrderBy(found => found))
{
if (!subKey.StartsWith(searchSubKey, StringComparison.InvariantCultureIgnoreCase))
{
continue;
}
if (string.Equals(subKey, searchSubKey, StringComparison.OrdinalIgnoreCase))
{
var key = parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree);
if (key != null)
{
list.Add(new RegistryEntry(key));
}
return list;
}
try
{
var key = parentKey.OpenSubKey(subKey, RegistryKeyPermissionCheck.ReadSubTree);
if (key != null)
{
list.Add(new RegistryEntry(key));
}
}
catch (Exception exception)
{
list.Add(new RegistryEntry($"{parentKey.Name}\\{subKey}", exception));
}
}
}
catch (Exception ex)
{
list.Add(new RegistryEntry(parentKey.Name, ex));
}
return list;
}
/// <summary>
/// Return a list with a registry sub-keys of the given registry parent-key
/// </summary>
/// <param name="parentKey">The registry parent-key</param>
/// <param name="maxCount">(optional) The maximum count of the results</param>
/// <returns>A list with all found registry sub-keys</returns>
private static Collection<RegistryEntry> GetAllSubKeys(in RegistryKey parentKey, in int maxCount = 50)
{
var list = new Collection<RegistryEntry>();
try
{
foreach (var subKey in parentKey.GetSubKeyNames())
{
if (list.Count >= maxCount)
{
break;
}
list.Add(new RegistryEntry(parentKey));
}
}
catch (Exception exception)
{
list.Add(new RegistryEntry(parentKey.Name, exception));
}
return list;
}
}

View File

@@ -0,0 +1,205 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Commands;
using Microsoft.CmdPal.Ext.Registry.Constants;
using Microsoft.CmdPal.Ext.Registry.Enumerations;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.Registry.Helpers;
/// <summary>
/// Helper class to easier work with results
/// </summary>
internal static class ResultHelper
{
/// <summary>
/// Return a list with <see cref="Result"/>s, based on the given list
/// </summary>
/// <param name="list">The original result list to convert</param>
/// <returns>A list with <see cref="Result"/></returns>
internal static List<ListItem> GetResultList(in IEnumerable<RegistryEntry> list)
{
var resultList = new List<ListItem>();
foreach (var entry in list)
{
var result = new ListItem(new OpenKeyInEditorCommand(entry))
{
Icon = RegistryListPage.RegistryIcon,
MoreCommands = ContextMenuHelper.GetContextMenu(entry).ToArray(),
};
if (entry.Exception is null && entry.Key is not null)
{
// when key contains keys or fields
result.TextToSuggest = entry.Key.Name;
result.Subtitle = RegistryHelper.GetSummary(entry.Key);
result.Title = GetTruncatedText(entry.Key.Name, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
}
else if (entry.Key is null && entry.Exception is not null)
{
// on error (e.g access denied)
result.TextToSuggest = entry.KeyPath;
result.Subtitle = GetTruncatedText(entry.Exception.Message, MaxTextLength.MaximumSubTitleLengthWithTwoSymbols, TruncateSide.OnlyFromRight);
result.Title = GetTruncatedText(entry.KeyPath, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
}
else
{
result.TextToSuggest = entry.KeyPath;
result.Title = GetTruncatedText(entry.KeyPath, MaxTextLength.MaximumTitleLengthWithTwoSymbols);
}
// result.ContextData = entry;
// TODO GH #126 Investigate tool tips, result.ToolTipData = new ToolTipData(Resources.RegistryKey, $"{Resources.KeyName} {result.Title}");
resultList.Add(result);
}
return resultList;
}
#pragma warning disable CS8632
internal static List<ListItem> GetValuesFromKey(in RegistryKey? key, string searchValue = "")
{
#pragma warning restore CS8632
if (key is null)
{
return [];
}
var valueList = new List<KeyValuePair<string, object>>(key.ValueCount);
var resultList = new List<ListItem>();
try
{
var valueNames = key.GetValueNames();
try
{
foreach (var valueName in valueNames)
{
var value = key.GetValue(valueName);
if (value != null)
{
valueList.Add(KeyValuePair.Create(valueName, value));
}
}
}
catch (Exception valueException)
{
var registryEntry = new RegistryEntry(key.Name, valueException);
resultList.Add(new ListItem(new OpenKeyInEditorCommand(registryEntry))
{
Icon = RegistryListPage.RegistryIcon,
Subtitle = GetTruncatedText(valueException.Message, MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
Title = GetTruncatedText(key.Name, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
MoreCommands = ContextMenuHelper.GetContextMenu(registryEntry).ToArray(),
// TODO --> Investigate ToolTipData = new ToolTipData(valueException.Message, valueException.ToString()),
});
}
if (!string.IsNullOrEmpty(searchValue))
{
var filteredValueName = valueList.Where(found => found.Key.Contains(searchValue, StringComparison.InvariantCultureIgnoreCase));
var filteredValueList = valueList.Where(found => found.Value.ToString()?.Contains(searchValue, StringComparison.InvariantCultureIgnoreCase) ?? false);
valueList = filteredValueName.Concat(filteredValueList).Distinct().ToList();
}
foreach (var valueEntry in valueList.OrderBy(found => found.Key))
{
var valueName = valueEntry.Key;
if (string.IsNullOrEmpty(valueName))
{
valueName = "(Default)";
}
var registryEntry = new RegistryEntry(key, valueEntry.Key, valueEntry.Value);
resultList.Add(new ListItem(new OpenKeyInEditorCommand(registryEntry))
{
Icon = RegistryListPage.RegistryIcon,
Subtitle = GetTruncatedText(GetSubTileForRegistryValue(key, valueEntry), MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
Title = GetTruncatedText(valueName, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
MoreCommands = ContextMenuHelper.GetContextMenu(registryEntry).ToArray(),
// TODO Investigate -->ToolTipData = new ToolTipData(Resources.RegistryValue, GetToolTipTextForRegistryValue(key, valueEntry)),
});
}
}
catch (Exception exception)
{
var registryEntry = new RegistryEntry(key.Name, exception);
resultList.Add(new ListItem(new OpenKeyInEditorCommand(registryEntry))
{
Icon = RegistryListPage.RegistryIcon,
Subtitle = GetTruncatedText(exception.Message, MaxTextLength.MaximumSubTitleLengthWithThreeSymbols, TruncateSide.OnlyFromRight),
Title = GetTruncatedText(key.Name, MaxTextLength.MaximumTitleLengthWithThreeSymbols),
});
}
return resultList;
}
/// <summary>
/// Return a truncated name
/// </summary>
/// <param name="text">The text to truncate</param>
/// <param name="maxLength">The maximum length of the text</param>
/// <param name="truncateSide">(optional) The side of the truncate</param>
/// <returns>A truncated text with a maximum length</returns>
internal static string GetTruncatedText(string text, in int maxLength, TruncateSide truncateSide = TruncateSide.OnlyFromLeft)
{
if (truncateSide == TruncateSide.OnlyFromLeft)
{
if (text.Length > maxLength)
{
text = QueryHelper.GetKeyWithShortBaseKey(text);
}
return text.Length > maxLength ? $"...{text[^maxLength..]}" : text;
}
else
{
return text.Length > maxLength ? $"{text[0..maxLength]}..." : text;
}
}
/// <summary>
/// Return the tool-tip text for a registry value
/// </summary>
/// <param name="key">The registry key for the tool-tip</param>
/// <param name="valueEntry">The value name and value of the registry value</param>
/// <returns>A tool-tip text</returns>
private static string GetToolTipTextForRegistryValue(RegistryKey key, KeyValuePair<string, object> valueEntry)
{
return $"{Resources.KeyName} {key.Name}{Environment.NewLine}"
+ $"{Resources.Name} {valueEntry.Key}{Environment.NewLine}"
+ $"{Resources.Type} {ValueHelper.GetType(key, valueEntry.Key)}{Environment.NewLine}"
+ $"{Resources.Value} {ValueHelper.GetValue(key, valueEntry.Key)}";
}
/// <summary>
/// Return the sub-title text for a registry value
/// </summary>
/// <param name="key">The registry key for the sub-title</param>
/// <param name="valueEntry">The value name and value of the registry value</param>
/// <returns>A sub-title text</returns>
private static string GetSubTileForRegistryValue(RegistryKey key, KeyValuePair<string, object> valueEntry)
{
return $"{Resources.Type} {ValueHelper.GetType(key, valueEntry.Key)}"
+ $" - {Resources.Value} {ValueHelper.GetValue(key, valueEntry.Key, 50)}";
}
}

View File

@@ -0,0 +1,70 @@
// 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.Linq;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.Win32;
namespace Microsoft.CmdPal.Ext.Registry.Helpers;
/// <summary>
/// Helper class to easier work with values of a <see cref="RegistryKey"/>
/// </summary>
internal static class ValueHelper
{
/// <summary>
/// Return a human readable value data, of the given value name inside the given <see cref="RegistryKey"/>
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> that should contain the value name.</param>
/// <param name="valueName">The name of the value.</param>
/// <param name="maxLength">The maximum length for the human readable value.</param>
/// <returns>A human readable value data.</returns>
internal static string GetValue(in RegistryKey key, in string valueName, int maxLength = int.MaxValue)
{
var unformattedValue = key.GetValue(valueName);
if (unformattedValue == null)
{
throw new InvalidOperationException($"Cannot proceed when {nameof(unformattedValue)} is null.");
}
var valueData = key.GetValueKind(valueName) switch
{
RegistryValueKind.DWord => $"0x{unformattedValue:X8} ({(uint)(int)unformattedValue})",
RegistryValueKind.QWord => $"0x{unformattedValue:X16} ({(ulong)(long)unformattedValue})",
#pragma warning disable CS8604 // Possible null reference argument.
RegistryValueKind.Binary => (unformattedValue as byte[]).Aggregate(string.Empty, (current, singleByte) => $"{current} {singleByte:X2}"),
#pragma warning restore CS8604 // Possible null reference argument.
_ => $"{unformattedValue}",
};
return valueData.Length > maxLength
? $"{valueData.Substring(0, maxLength)}..."
: valueData;
}
/// <summary>
/// Return the registry type name of a given value name inside a given <see cref="RegistryKey"/>
/// </summary>
/// <param name="key">The <see cref="RegistryKey"/> that should contain the value name</param>
/// <param name="valueName">The name of the value</param>
/// <returns>A registry type name</returns>
internal static object GetType(RegistryKey key, string valueName)
{
return key.GetValueKind(valueName) switch
{
RegistryValueKind.None => Resources.RegistryValueKindNone,
RegistryValueKind.Unknown => Resources.RegistryValueKindUnknown,
RegistryValueKind.String => "REG_SZ",
RegistryValueKind.ExpandString => "REG_EXPAND_SZ",
RegistryValueKind.MultiString => "REG_MULTI_SZ",
RegistryValueKind.Binary => "REG_BINARY",
RegistryValueKind.DWord => "REG_DWORD",
RegistryValueKind.QWord => "REG_QWORD",
_ => throw new ArgumentOutOfRangeException(nameof(valueName)),
};
}
}

View File

@@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.Registry</RootNamespace>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
<ProjectPriFileName>Microsoft.CmdPal.Ext.Registry.pri</ProjectPriFileName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceProcess.ServiceController" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Registry.svg" />
</ItemGroup>
<ItemGroup>
<Content Update="Assets\Registry.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="Assets\Registry.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,78 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.CmdPal.Ext.Registry.Classes;
using Microsoft.CmdPal.Ext.Registry.Helpers;
using Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.Registry;
internal sealed partial class RegistryListPage : DynamicListPage
{
public static IconInfo RegistryIcon { get; } = new("\uE74C"); // OEM
private readonly CommandItem _emptyMessage;
public RegistryListPage()
{
Icon = IconHelpers.FromRelativePath("Assets\\Registry.svg");
Name = Title = Resources.Registry_Page_Title;
Id = "com.microsoft.cmdpal.registry";
_emptyMessage = new CommandItem()
{
Icon = IconHelpers.FromRelativePath("Assets\\Registry.svg"),
Title = Resources.Registry_Key_Not_Found,
Subtitle = SearchText,
};
EmptyContent = _emptyMessage;
}
public List<ListItem> Query(string query)
{
if (query is null)
{
return [];
}
var searchForValueName = QueryHelper.GetQueryParts(query, out var queryKey, out var queryValueName);
var (baseKeyList, subKey) = RegistryHelper.GetRegistryBaseKey(queryKey);
if (baseKeyList is null)
{
// no base key found
return ResultHelper.GetResultList(RegistryHelper.GetAllBaseKeys());
}
else if (baseKeyList.Count() == 1)
{
// only one base key was found -> start search for the sub-key
var list = RegistryHelper.SearchForSubKey(baseKeyList.First(), subKey);
// when only one sub-key was found and a user search for values ("\\")
// show the filtered list of values of one sub-key
return searchForValueName && list.Count == 1
? ResultHelper.GetValuesFromKey(list.First().Key, queryValueName)
: ResultHelper.GetResultList(list);
}
else if (baseKeyList.Count() > 1)
{
// more than one base key was found -> show results
return ResultHelper.GetResultList(baseKeyList.Select(found => new RegistryEntry(found)));
}
return [];
}
public override void UpdateSearchText(string oldSearch, string newSearch)
{
_emptyMessage.Subtitle = newSearch;
RaiseItemsChanged(0);
}
public override IListItem[] GetItems() => Query(SearchText).ToArray();
}

View File

@@ -0,0 +1,252 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.CmdPal.Ext.Registry.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CmdPal.Ext.Registry.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Copy key name (path).
/// </summary>
internal static string CopyKeyNamePath {
get {
return ResourceManager.GetString("CopyKeyNamePath", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy value data.
/// </summary>
internal static string CopyValueData {
get {
return ResourceManager.GetString("CopyValueData", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy value name.
/// </summary>
internal static string CopyValueName {
get {
return ResourceManager.GetString("CopyValueName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Key name:.
/// </summary>
internal static string KeyName {
get {
return ResourceManager.GetString("KeyName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Name:.
/// </summary>
internal static string Name {
get {
return ResourceManager.GetString("Name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You do not have enough rights to open the Windows registry editor.
/// </summary>
internal static string OpenInRegistryEditorAccessExceptionText {
get {
return ResourceManager.GetString("OpenInRegistryEditorAccessExceptionText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error on open registry editor.
/// </summary>
internal static string OpenInRegistryEditorAccessExceptionTitle {
get {
return ResourceManager.GetString("OpenInRegistryEditorAccessExceptionTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open key in registry editor.
/// </summary>
internal static string OpenKeyInRegistryEditor {
get {
return ResourceManager.GetString("OpenKeyInRegistryEditor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Navigates inside the Windows Registry.
/// </summary>
internal static string PluginDescription {
get {
return ResourceManager.GetString("PluginDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Registry Plugin.
/// </summary>
internal static string PluginTitle {
get {
return ResourceManager.GetString("PluginTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Registry key not found.
/// </summary>
internal static string Registry_Key_Not_Found {
get {
return ResourceManager.GetString("Registry_Key_Not_Found", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Windows Registry.
/// </summary>
internal static string Registry_Page_Title {
get {
return ResourceManager.GetString("Registry_Page_Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Registry key.
/// </summary>
internal static string RegistryKey {
get {
return ResourceManager.GetString("RegistryKey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Windows Registry.
/// </summary>
internal static string RegistryProvider_DisplayName {
get {
return ResourceManager.GetString("RegistryProvider_DisplayName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Registry value.
/// </summary>
internal static string RegistryValue {
get {
return ResourceManager.GetString("RegistryValue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No data type.
/// </summary>
internal static string RegistryValueKindNone {
get {
return ResourceManager.GetString("RegistryValueKindNone", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unsupported data type.
/// </summary>
internal static string RegistryValueKindUnknown {
get {
return ResourceManager.GetString("RegistryValueKindUnknown", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Subkeys:.
/// </summary>
internal static string SubKeys {
get {
return ResourceManager.GetString("SubKeys", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type:.
/// </summary>
internal static string Type {
get {
return ResourceManager.GetString("Type", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Value:.
/// </summary>
internal static string Value {
get {
return ResourceManager.GetString("Value", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Values:.
/// </summary>
internal static string Values {
get {
return ResourceManager.GetString("Values", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="PluginTitle" xml:space="preserve">
<value>Registry Plugin</value>
</data>
<data name="PluginDescription" xml:space="preserve">
<value>Navigates inside the Windows Registry</value>
<comment>"this built into Windows the OS. translate accordingly, https://learn.microsoft.com/troubleshoot/windows-server/performance/windows-registry-advanced-users is an example of it translated in German"</comment>
</data>
<data name="CopyKeyNamePath" xml:space="preserve">
<value>Copy key name (path)</value>
<comment>'The maximum size of a key name is 255 characters.'</comment>
</data>
<data name="KeyName" xml:space="preserve">
<value>Key name:</value>
<comment>'The maximum size of a key name is 255 characters.'</comment>
</data>
<data name="Name" xml:space="preserve">
<value>Name:</value>
</data>
<data name="CopyValueName" xml:space="preserve">
<value>Copy value name</value>
</data>
<data name="OpenKeyInRegistryEditor" xml:space="preserve">
<value>Open key in registry editor</value>
<comment>"registry editor" is the name of the OS built-in application</comment>
</data>
<data name="OpenInRegistryEditorAccessExceptionText" xml:space="preserve">
<value>You do not have enough rights to open the Windows registry editor</value>
<comment>"registry editor" is the name of the OS built-in application </comment>
</data>
<data name="OpenInRegistryEditorAccessExceptionTitle" xml:space="preserve">
<value>Error on open registry editor</value>
<comment>"registry editor" is the name of the OS built-in application</comment>
</data>
<data name="SubKeys" xml:space="preserve">
<value>Subkeys:</value>
</data>
<data name="Values" xml:space="preserve">
<value>Values:</value>
</data>
<data name="RegistryKey" xml:space="preserve">
<value>Registry key</value>
</data>
<data name="RegistryValue" xml:space="preserve">
<value>Registry value</value>
</data>
<data name="Type" xml:space="preserve">
<value>Type:</value>
<comment>See https://learn.microsoft.com/windows/win32/sysinfo/registry-value-types for proper context of how to translate 'type'</comment>
</data>
<data name="Value" xml:space="preserve">
<value>Value:</value>
<comment>See https://learn.microsoft.com/windows/win32/sysinfo/registry-value-types for proper context of how to translate 'value'</comment>
</data>
<data name="RegistryValueKindNone" xml:space="preserve">
<value>No data type</value>
</data>
<data name="RegistryValueKindUnknown" xml:space="preserve">
<value>Unsupported data type</value>
</data>
<data name="CopyValueData" xml:space="preserve">
<value>Copy value data</value>
</data>
<data name="Registry_Page_Title" xml:space="preserve">
<value>Windows Registry</value>
</data>
<data name="Registry_Key_Not_Found" xml:space="preserve">
<value>Registry key not found</value>
</data>
<data name="RegistryProvider_DisplayName" xml:space="preserve">
<value>Windows Registry</value>
</data>
</root>

View File

@@ -0,0 +1,30 @@
// 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 Microsoft.CmdPal.Ext.Registry.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.Registry;
public partial class RegistryCommandsProvider : CommandProvider
{
public RegistryCommandsProvider()
{
Id = "Windows.Registry";
DisplayName = Resources.RegistryProvider_DisplayName;
Icon = IconHelpers.FromRelativePath("Assets\\Registry.svg");
}
public override ICommandItem[] TopLevelCommands()
{
return [
new CommandItem(new RegistryListPage())
{
Title = "Registry",
Subtitle = "Navigate the Windows registry",
}
];
}
}