diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index 46df0235d8..d4be728886 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -1798,6 +1798,7 @@ tlbimp
tlc
tmain
TNP
+toolgood
Toolhelp
toolwindow
TOPDOWNDIB
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 00db38f4df..26e2c83bcc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -122,6 +122,7 @@
+
diff --git a/NOTICE.md b/NOTICE.md
index 6ca3cbfceb..23efb64864 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -75,6 +75,37 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
```
+### ToolGood.Words.Pinyin
+
+We use the ToolGood.Words.Pinyin NuGet package for converting Chinese characters to pinyin.
+
+**Source**: [https://github.com/toolgood/ToolGood.Words.Pinyin](https://github.com/toolgood/ToolGood.Words.Pinyin)
+
+```
+MIT License
+
+Copyright (c) 2020 ToolGood
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
+
+
## Utility: Command Palette Built-in Extensions
### Calculator
@@ -1532,6 +1563,7 @@ SOFTWARE.
- SkiaSharp.Views.WinUI
- StreamJsonRpc
- StyleCop.Analyzers
+- ToolGood.Words.Pinyin
- UnicodeInformation
- UnitsNet
- UTF.Unknown
diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/FuzzyStringMatcher.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/FuzzyStringMatcher.cs
index f4591bc443..7ecfc74222 100644
--- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/FuzzyStringMatcher.cs
+++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/FuzzyStringMatcher.cs
@@ -2,6 +2,10 @@
// 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.Globalization;
+
+using ToolGood.Words.Pinyin;
+
namespace Microsoft.CommandPalette.Extensions.Toolkit;
// Inspired by the fuzzy.rs from edit.exe
@@ -9,6 +13,21 @@ public static class FuzzyStringMatcher
{
private const int NOMATCH = 0;
+ ///
+ /// Gets a value indicating whether to support Chinese PinYin.
+ /// Automatically enabled when the system UI culture is Simplified Chinese.
+ ///
+ public static bool ChinesePinYinSupport { get; } = IsSimplifiedChinese();
+
+ private static bool IsSimplifiedChinese()
+ {
+ var culture = CultureInfo.CurrentUICulture;
+
+ // Detect Simplified Chinese: zh-CN, zh-Hans, zh-Hans-*
+ return culture.Name.StartsWith("zh-CN", StringComparison.OrdinalIgnoreCase)
+ || culture.Name.StartsWith("zh-Hans", StringComparison.OrdinalIgnoreCase);
+ }
+
public static int ScoreFuzzy(string needle, string haystack, bool allowNonContiguousMatches = true)
{
var (s, _) = ScoreFuzzyWithPositions(needle, haystack, allowNonContiguousMatches);
@@ -16,6 +35,28 @@ public static class FuzzyStringMatcher
}
public static (int Score, List Positions) ScoreFuzzyWithPositions(string needle, string haystack, bool allowNonContiguousMatches)
+ => ScoreAllFuzzyWithPositions(needle, haystack, allowNonContiguousMatches).MaxBy(i => i.Score);
+
+ public static IEnumerable<(int Score, List Positions)> ScoreAllFuzzyWithPositions(string needle, string haystack, bool allowNonContiguousMatches)
+ {
+ List needles = [needle];
+ List haystacks = [haystack];
+
+ if (ChinesePinYinSupport)
+ {
+ // Remove IME composition split characters.
+ var input = needle.Replace("'", string.Empty);
+ needles.Add(WordsHelper.GetPinyin(input));
+ if (WordsHelper.HasChinese(haystack))
+ {
+ haystacks.Add(WordsHelper.GetPinyin(haystack));
+ }
+ }
+
+ return needles.SelectMany(i => haystacks.Select(j => ScoreFuzzyWithPositionsInternal(i, j, allowNonContiguousMatches)));
+ }
+
+ private static (int Score, List Positions) ScoreFuzzyWithPositionsInternal(string needle, string haystack, bool allowNonContiguousMatches)
{
if (string.IsNullOrEmpty(haystack) || string.IsNullOrEmpty(needle))
{
diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Microsoft.CommandPalette.Extensions.Toolkit.csproj b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Microsoft.CommandPalette.Extensions.Toolkit.csproj
index f5f8f2ccbc..eb887e9e36 100644
--- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Microsoft.CommandPalette.Extensions.Toolkit.csproj
+++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/Microsoft.CommandPalette.Extensions.Toolkit.csproj
@@ -42,6 +42,7 @@
runtime; build; native; contentfiles; analyzers
+