Compare commits

...

1 Commits

Author SHA1 Message Date
Yu Leng (from Dev Box)
2cf6b03511 Using Settings in StringMatcher 2025-08-22 15:35:24 +08:00
24 changed files with 250 additions and 46 deletions

View File

@@ -13,7 +13,8 @@ using Windows.System;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ContextMenuViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
IRecipient<UpdateCommandBarMessage>,
IRecipient<UpdatePinyinSettingsMessage>
{
public ICommandBarContext? SelectedItem
{
@@ -38,9 +39,18 @@ public partial class ContextMenuViewModel : ObservableObject,
private string _lastSearchText = string.Empty;
public ContextMenuViewModel()
private MatchOption _matchOption;
public ContextMenuViewModel(MatchOption option)
{
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
WeakReferenceMessenger.Default.Register<UpdatePinyinSettingsMessage>(this);
_matchOption = option;
}
public ContextMenuViewModel()
: this(new MatchOption() { Language = MatchLanguage.English })
{
}
public void Receive(UpdateCommandBarMessage message)
@@ -48,6 +58,17 @@ public partial class ContextMenuViewModel : ObservableObject,
SelectedItem = message.ViewModel;
}
public void Receive(UpdatePinyinSettingsMessage message)
{
_matchOption.Language = message.IsPinyinInput ? MatchLanguage.Chinese : MatchLanguage.English;
// Refresh the search results if there's an active search
if (!string.IsNullOrEmpty(_lastSearchText))
{
SetSearchText(_lastSearchText);
}
}
public void UpdateContextItems()
{
if (SelectedItem is not null)
@@ -94,7 +115,7 @@ public partial class ContextMenuViewModel : ObservableObject,
ListHelpers.InPlaceUpdateList(FilteredItems, newResults);
}
private static int ScoreContextCommand(string query, CommandContextItemViewModel item)
private int ScoreContextCommand(string query, CommandContextItemViewModel item)
{
if (string.IsNullOrEmpty(query) || string.IsNullOrWhiteSpace(query))
{
@@ -106,9 +127,9 @@ public partial class ContextMenuViewModel : ObservableObject,
return 0;
}
var nameMatch = StringMatcher.FuzzySearch(query, item.Title);
var nameMatch = StringMatcher.FuzzySearch(query, item.Title, _matchOption.Language);
var descriptionMatch = StringMatcher.FuzzySearch(query, item.Subtitle);
var descriptionMatch = StringMatcher.FuzzySearch(query, item.Subtitle, _matchOption.Language);
return new[] { nameMatch.Score, (descriptionMatch.Score - 4) / 2, 0 }.Max();
}

View File

@@ -9,7 +9,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ListItemViewModel(IListItem model, WeakReference<IPageContext> context)
public partial class ListItemViewModel(IListItem model, WeakReference<IPageContext> context, MatchOption matchOption)
: CommandItemViewModel(new(model), context)
{
public new ExtensionObject<IListItem> Model { get; } = new(model);
@@ -29,6 +29,8 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
[MemberNotNullWhen(true, nameof(Details))]
public bool HasDetails => Details is not null;
private MatchOption _matchOption = matchOption;
public override void InitializeProperties()
{
if (IsInitialized)
@@ -97,7 +99,7 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
// TODO: Do we want filters to match descriptions and other properties? Tags, etc... Yes?
// TODO: Do we want to save off the score here so we can sort by it in our ListViewModel?
public bool MatchesFilter(string filter) => StringMatcher.FuzzySearch(filter, Title).Success || StringMatcher.FuzzySearch(filter, Subtitle).Success;
public bool MatchesFilter(string filter) => StringMatcher.FuzzySearch(filter, Title, _matchOption.Language).Success || StringMatcher.FuzzySearch(filter, Subtitle, _matchOption.Language).Success;
public override string ToString() => $"{Name} ListItemViewModel";

View File

@@ -67,6 +67,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
private ListItemViewModel? _lastSelectedItem;
private MatchOption _matchOption;
public override bool IsInitialized
{
get => base.IsInitialized; protected set
@@ -76,11 +78,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
}
}
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host)
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, MatchOption matchOption)
: base(model, scheduler, host)
{
_model = new(model);
EmptyContent = new(new(null), PageContext);
_matchOption = matchOption;
}
// TODO: Does this need to hop to a _different_ thread, so that we don't block the extension while we're fetching?
@@ -162,7 +165,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
// Check for cancellation during item processing
cancellationToken.ThrowIfCancellationRequested();
ListItemViewModel viewModel = new(item, new(this));
ListItemViewModel viewModel = new(item, new(this), _matchOption);
// If an item fails to load, silently ignore it.
if (viewModel.SafeFastInit())
@@ -305,22 +308,22 @@ public partial class ListViewModel : PageViewModel, IDisposable
/// Apply our current filter text to the list of items, and update
/// FilteredItems to match the results.
/// </summary>
private void ApplyFilterUnderLock() => ListHelpers.InPlaceUpdateList(FilteredItems, FilterList(Items, Filter));
private void ApplyFilterUnderLock() => ListHelpers.InPlaceUpdateList(FilteredItems, FilterList(Items, Filter, _matchOption.Language));
/// <summary>
/// Helper to generate a weighting for a given list item, based on title,
/// subtitle, etc. Largely a copy of the version in ListHelpers, but
/// operating on ViewModels instead of extension objects.
/// </summary>
private static int ScoreListItem(string query, CommandItemViewModel listItem)
private static int ScoreListItem(string query, CommandItemViewModel listItem, MatchLanguage language)
{
if (string.IsNullOrEmpty(query))
{
return 1;
}
var nameMatch = StringMatcher.FuzzySearch(query, listItem.Title);
var descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle);
var nameMatch = StringMatcher.FuzzySearch(query, listItem.Title, language);
var descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle, language);
return new[] { nameMatch.Score, (descriptionMatch.Score - 4) / 2, 0 }.Max();
}
@@ -331,11 +334,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
}
// Similarly stolen from ListHelpers.FilterList
public static IEnumerable<ListItemViewModel> FilterList(IEnumerable<ListItemViewModel> items, string query)
public static IEnumerable<ListItemViewModel> FilterList(IEnumerable<ListItemViewModel> items, string query, MatchLanguage language)
{
var scores = items
.Where(i => !i.IsInErrorState)
.Select(li => new ScoredListItemViewModel() { ViewModel = li, Score = ScoreListItem(query, li) })
.Select(li => new ScoredListItemViewModel() { ViewModel = li, Score = ScoreListItem(query, li, language) })
.Where(score => score.Score > 0)
.OrderByDescending(score => score.Score);
return scores

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.Core.ViewModels.Messages;
/// <summary>
/// Used to update the pinyin input settings in context menu and other components
/// </summary>
public record UpdatePinyinSettingsMessage(bool IsPinyinInput)
{
}

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.UI.ViewModels;
@@ -11,17 +12,25 @@ public class CommandPalettePageViewModelFactory
: IPageViewModelFactoryService
{
private readonly TaskScheduler _scheduler;
private readonly SettingsModel _settingsModel;
public CommandPalettePageViewModelFactory(TaskScheduler scheduler)
public CommandPalettePageViewModelFactory(TaskScheduler scheduler, SettingsModel settingsModel)
{
_scheduler = scheduler;
_settingsModel = settingsModel ?? throw new ArgumentNullException(nameof(settingsModel));
}
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
{
var isPinyinInput = _settingsModel.IsPinYinInput;
var matchOptions = new MatchOption
{
Language = isPinyinInput ? MatchLanguage.Chinese : MatchLanguage.English,
};
return page switch
{
IListPage listPage => new ListViewModel(listPage, _scheduler, host) { IsNested = nested },
IListPage listPage => new ListViewModel(listPage, _scheduler, host, matchOptions) { IsNested = nested },
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, _scheduler, host),
_ => null,
};

View File

@@ -34,6 +34,8 @@ public partial class MainListPage : DynamicListPage,
private InterlockedBoolean _refreshRunning;
private InterlockedBoolean _refreshRequested;
private MatchLanguage _matchLanague;
public MainListPage(IServiceProvider serviceProvider)
{
Icon = IconHelpers.FromRelativePath("Assets\\StoreLogo.scale-200.png");
@@ -296,19 +298,19 @@ public partial class MainListPage : DynamicListPage,
// * otherwise full weight match
var nameMatch = isWhiteSpace ?
(title.Contains(query) ? 1 : 0) :
StringMatcher.FuzzySearch(query, title).Score;
StringMatcher.FuzzySearch(query, title, _matchLanague).Score;
// Subtitle:
// * whitespace query: 1/2 point
// * otherwise ~half weight match. Minus a bit, because subtitles tend to be longer
var descriptionMatch = isWhiteSpace ?
(topLevelOrAppItem.Subtitle.Contains(query) ? .5 : 0) :
(StringMatcher.FuzzySearch(query, topLevelOrAppItem.Subtitle).Score - 4) / 2.0;
(StringMatcher.FuzzySearch(query, topLevelOrAppItem.Subtitle, _matchLanague).Score - 4) / 2.0;
// Extension title: despite not being visible, give the extension name itself some weight
// * whitespace query: 0 points
// * otherwise more weight than a subtitle, but not much
var extensionTitleMatch = isWhiteSpace ? 0 : StringMatcher.FuzzySearch(query, extensionDisplayName).Score / 1.5;
var extensionTitleMatch = isWhiteSpace ? 0 : StringMatcher.FuzzySearch(query, extensionDisplayName, _matchLanague).Score / 1.5;
var scores = new[]
{
@@ -370,5 +372,9 @@ public partial class MainListPage : DynamicListPage,
private void SettingsChangedHandler(SettingsModel sender, object? args) => HotReloadSettings(sender);
private void HotReloadSettings(SettingsModel settings) => ShowDetails = settings.ShowAppDetails;
private void HotReloadSettings(SettingsModel settings)
{
ShowDetails = settings.ShowAppDetails;
_matchLanague = settings.IsPinYinInput ? MatchLanguage.Chinese : MatchLanguage.English;
}
}

View File

@@ -7,6 +7,8 @@ using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
@@ -42,6 +44,20 @@ public partial class SettingsModel : ObservableObject
public bool IgnoreShortcutWhenFullscreen { get; set; }
private bool _isPinYinInput;
public bool IsPinYinInput
{
get => _isPinYinInput;
set
{
if (SetProperty(ref _isPinYinInput, value))
{
WeakReferenceMessenger.Default.Send(new UpdatePinyinSettingsMessage(value));
}
}
}
public Dictionary<string, ProviderSettings> ProviderSettings { get; set; } = [];
public Dictionary<string, CommandAlias> Aliases { get; set; } = [];

View File

@@ -118,6 +118,16 @@ public partial class SettingsViewModel : INotifyPropertyChanged
}
}
public bool IsPinYinInput
{
get => _settings.IsPinYinInput;
set
{
_settings.IsPinYinInput = value;
Save();
}
}
public ObservableCollection<ProviderSettingsViewModel> CommandProviders { get; } = [];
public SettingsViewModel(SettingsModel settings, IServiceProvider serviceProvider, TaskScheduler scheduler)

View File

@@ -132,14 +132,6 @@ public partial class App : Application
Logger.LogError(ex.ToString());
}
services.AddSingleton<ICommandProvider, WindowsTerminalCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsSettingsCommandsProvider>();
services.AddSingleton<ICommandProvider, RegistryCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsServicesCommandsProvider>();
services.AddSingleton<ICommandProvider, BuiltInsCommandProvider>();
services.AddSingleton<ICommandProvider, TimeDateCommandsProvider>();
services.AddSingleton<ICommandProvider, SystemCommandExtensionProvider>();
// Models
services.AddSingleton<TopLevelCommandManager>();
services.AddSingleton<AliasManager>();
@@ -156,10 +148,20 @@ public partial class App : Application
services.AddSingleton<IAppHostService, PowerToysAppHostService>();
services.AddSingleton(new TelemetryForwarder());
services.AddSingleton<ICommandProvider, WindowsTerminalCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsSettingsCommandsProvider>();
services.AddSingleton<ICommandProvider, RegistryCommandsProvider>();
services.AddSingleton<ICommandProvider, WindowsServicesCommandsProvider>();
services.AddSingleton<ICommandProvider, BuiltInsCommandProvider>();
services.AddSingleton<ICommandProvider>(provider => new TimeDateCommandsProvider(sm.IsPinYinInput));
services.AddSingleton<ICommandProvider, SystemCommandExtensionProvider>();
// ViewModels
services.AddSingleton<ShellViewModel>();
services.AddSingleton<IPageViewModelFactoryService, CommandPalettePageViewModelFactory>();
return services.BuildServiceProvider();
var serviceProvider = services.BuildServiceProvider();
return serviceProvider;
}
}

View File

@@ -53,7 +53,7 @@
Opened="ContextMenuFlyout_Opened"
ShouldConstrainToRootBounds="False"
SystemBackdrop="{ThemeResource AcrylicBackgroundFillColorDefaultBackdrop}">
<cpcontrols:ContextMenu x:Name="ContextControl" />
<cpcontrols:ContextMenu x:Name="ContextMenuControl" />
</Flyout>
<Style x:Key="HotkeyStyle" TargetType="Border">

View File

@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.Messages;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.Views;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -138,6 +139,9 @@ public sealed partial class CommandBar : UserControl,
{
// We need to wait until our flyout is opened to try and toss focus
// at its search box. The control isn't in the UI tree before that
ContextControl.FocusSearchBox();
if (ContextMenuFlyout.Content is ContextMenu contextMenu)
{
contextMenu.FocusSearchBox();
}
}
}

View File

@@ -6,6 +6,9 @@ using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.UI.Messages;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -18,11 +21,14 @@ namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class ContextMenu : UserControl,
IRecipient<OpenContextMenuMessage>,
IRecipient<UpdateCommandBarMessage>,
IRecipient<TryCommandKeybindingMessage>
IRecipient<TryCommandKeybindingMessage>,
IRecipient<UpdatePinyinSettingsMessage>
{
public ContextMenuViewModel ViewModel { get; } = new();
private bool _isPinyinInput;
public ContextMenu()
public ContextMenuViewModel ViewModel { get; private set; } = null!;
public ContextMenu(SettingsModel settingsModel)
{
this.InitializeComponent();
@@ -30,6 +36,10 @@ public sealed partial class ContextMenu : UserControl,
WeakReferenceMessenger.Default.Register<OpenContextMenuMessage>(this);
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
WeakReferenceMessenger.Default.Register<TryCommandKeybindingMessage>(this);
WeakReferenceMessenger.Default.Register<UpdatePinyinSettingsMessage>(this);
_isPinyinInput = settingsModel.IsPinYinInput;
ViewModel = new ContextMenuViewModel(new MatchOption() { Language = _isPinyinInput ? MatchLanguage.Chinese : MatchLanguage.English });
if (ViewModel is not null)
{
@@ -37,6 +47,11 @@ public sealed partial class ContextMenu : UserControl,
}
}
public ContextMenu()
: this(App.Current.Services.GetService<SettingsModel>()!)
{
}
public void Receive(OpenContextMenuMessage message)
{
ViewModel.FilterOnTop = message.ContextMenuFilterLocation == ContextMenuFilterLocation.Top;
@@ -71,6 +86,14 @@ public sealed partial class ContextMenu : UserControl,
}
}
public void Receive(UpdatePinyinSettingsMessage message)
{
_isPinyinInput = message.IsPinyinInput;
// Send the message to ViewModel to update its match option
ViewModel?.Receive(message);
}
private void CommandsDropdown_ItemClick(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is CommandContextItemViewModel item)

View File

@@ -84,6 +84,10 @@
<ToggleSwitch IsOn="{x:Bind viewModel.ShowSystemTrayIcon, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="Settings_GeneralPage_IsPinYinInput_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=&#xE98A;}">
<ToggleSwitch IsOn="{x:Bind viewModel.IsPinYinInput, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Example 'About' section -->
<TextBlock x:Uid="AboutSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />

View File

@@ -407,6 +407,12 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
<data name="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard.Description" xml:space="preserve">
<value>Choose if Command Palette is visible in the system tray</value>
</data>
<data name="Settings_GeneralPage_IsPinYinInput_SettingsCard.Header" xml:space="preserve">
<value>Input Chinese in CmdPal</value>
</data>
<data name="Settings_GeneralPage_IsPinYinInput_SettingsCard.Description" xml:space="preserve">
<value>Enable Chinese PinYin support</value>
</data>
<data name="BackButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Back</value>
</data>

View File

@@ -50,7 +50,7 @@ public class QueryTests : CommandPaletteUnitTestBase
var settings = new Settings();
// Act
var results = TimeDateCalculator.ExecuteSearch(settings, query);
var results = TimeDateCalculator.ExecuteSearch(settings, query, false);
// Assert
Assert.IsTrue(

View File

@@ -16,6 +16,7 @@ internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
private readonly HashSet<string> _validOptions;
private ISettingsInterface _settingsManager;
private DateTime? _timestamp;
private bool _isPinYinInput;
public FallbackTimeDateItem(ISettingsInterface settings, DateTime? timestamp = null)
: base(new NoOpCommand(), Resources.Microsoft_plugin_timedate_fallback_display_title)
@@ -24,6 +25,7 @@ internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
Subtitle = string.Empty;
_settingsManager = settings;
_timestamp = timestamp;
_isPinYinInput = false; // Default value
_validOptions = new(StringComparer.OrdinalIgnoreCase)
{
@@ -40,6 +42,17 @@ internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
};
}
public FallbackTimeDateItem(ISettingsInterface settings, bool isPinYinInput, DateTime? timestamp = null)
: this(settings, timestamp)
{
_isPinYinInput = isPinYinInput;
}
public void UpdatePinYinInput(bool isPinYinInput)
{
_isPinYinInput = isPinYinInput;
}
public override void UpdateQuery(string query)
{
if (!_settingsManager.EnableFallbackItems || string.IsNullOrWhiteSpace(query) || !IsValidQuery(query))
@@ -56,7 +69,7 @@ internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
foreach (var f in availableResults)
{
var score = f.Score(query, f.Label, f.AlternativeSearchTag);
var score = f.Score(query, f.Label, f.AlternativeSearchTag, _isPinYinInput);
if (score > maxScore)
{
maxScore = score;

View File

@@ -61,10 +61,10 @@ internal sealed class AvailableResult
};
}
public int Score(string query, string label, string tags)
public int Score(string query, string label, string tags, bool isPinyinInput)
{
// Get match for label (or for tags if label score is <1)
var score = StringMatcher.FuzzySearch(query, label).Score;
var score = StringMatcher.FuzzySearch(query, label, isPinyinInput ? MatchLanguage.Chinese : MatchLanguage.English).Score;
if (score < 1)
{
foreach (var t in tags.Split(";"))

View File

@@ -27,7 +27,7 @@ public sealed partial class TimeDateCalculator
/// </summary>
/// <param name="query">Search query object</param>
/// <returns>List of Wox <see cref="Result"/>s.</returns>
public static List<ListItem> ExecuteSearch(ISettingsInterface settings, string query)
public static List<ListItem> ExecuteSearch(ISettingsInterface settings, string query, bool isPinyinInput)
{
var isEmptySearchInput = string.IsNullOrWhiteSpace(query);
List<AvailableResult> availableFormats = new List<AvailableResult>();
@@ -82,7 +82,7 @@ public sealed partial class TimeDateCalculator
// Generate filtered list of results
foreach (var f in availableFormats)
{
var score = f.Score(query, f.Label, f.AlternativeSearchTag);
var score = f.Score(query, f.Label, f.AlternativeSearchTag, isPinyinInput);
if (score > 0)
{

View File

@@ -22,6 +22,11 @@
<ItemGroup>
<ProjectReference Include="..\..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
<ProjectReference Include="..\..\Microsoft.CmdPal.Core.ViewModels\Microsoft.CmdPal.Core.ViewModels.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" />
</ItemGroup>
<ItemGroup>

View File

@@ -21,7 +21,9 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
private ISettingsInterface _settingsManager;
public TimeDateExtensionPage(ISettingsInterface settingsManager)
private bool _isPinyinInput;
public TimeDateExtensionPage(ISettingsInterface settingsManager, bool isPinyinInput = false)
{
Icon = Icons.TimeDateExtIcon;
Title = Resources.Microsoft_plugin_timedate_main_page_title;
@@ -30,6 +32,12 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
Id = "com.microsoft.cmdpal.timedate";
_settingsManager = settingsManager;
ShowDetails = true;
_isPinyinInput = isPinyinInput;
}
public void UpdatePinyinInputSetting(bool flag)
{
_isPinyinInput = flag;
}
public override IListItem[] GetItems()
@@ -64,7 +72,7 @@ internal sealed partial class TimeDateExtensionPage : DynamicListPage
{
try
{
var result = TimeDateCalculator.ExecuteSearch(_settingsManager, query);
var result = TimeDateCalculator.ExecuteSearch(_settingsManager, query, _isPinyinInput);
UpdateResult(result);
}
catch (Exception)

View File

@@ -5,6 +5,8 @@
using System;
using System.Globalization;
using System.Text;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Ext.TimeDate.Helpers;
using Microsoft.CmdPal.Ext.TimeDate.Pages;
using Microsoft.CommandPalette.Extensions;
@@ -12,18 +14,26 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.TimeDate;
public partial class TimeDateCommandsProvider : CommandProvider
public partial class TimeDateCommandsProvider : CommandProvider, IRecipient<UpdatePinyinSettingsMessage>
{
private readonly CommandItem _command;
private static readonly SettingsManager _settingsManager = new SettingsManager();
private static readonly CompositeFormat MicrosoftPluginTimedatePluginDescription = System.Text.CompositeFormat.Parse(Resources.Microsoft_plugin_timedate_plugin_description);
private static readonly TimeDateExtensionPage _timeDateExtensionPage = new(_settingsManager);
private readonly FallbackTimeDateItem _fallbackTimeDateItem = new(_settingsManager);
private readonly TimeDateExtensionPage _timeDateExtensionPage;
private readonly FallbackTimeDateItem _fallbackTimeDateItem;
private bool _isPinYinInput;
public TimeDateCommandsProvider()
: this(false)
{
}
public TimeDateCommandsProvider(bool isPinYinInput)
{
DisplayName = Resources.Microsoft_plugin_timedate_plugin_name;
Id = "DateTime";
_timeDateExtensionPage = new TimeDateExtensionPage(_settingsManager, isPinYinInput);
_command = new CommandItem(_timeDateExtensionPage)
{
Icon = _timeDateExtensionPage.Icon,
@@ -34,6 +44,23 @@ public partial class TimeDateCommandsProvider : CommandProvider
Icon = _timeDateExtensionPage.Icon;
Settings = _settingsManager.Settings;
_isPinYinInput = isPinYinInput;
_fallbackTimeDateItem = new FallbackTimeDateItem(_settingsManager, isPinYinInput);
// Register for PinYin settings updates
WeakReferenceMessenger.Default.Register<UpdatePinyinSettingsMessage>(this);
}
public void UpdatePinYinInput(bool isPinYinInput)
{
_isPinYinInput = isPinYinInput;
_fallbackTimeDateItem.UpdatePinYinInput(isPinYinInput);
_timeDateExtensionPage.UpdatePinyinInputSetting(isPinYinInput);
}
public void Receive(UpdatePinyinSettingsMessage message)
{
UpdatePinYinInput(message.IsPinyinInput);
}
private string GetTranslatedPluginDescription()

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.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CommandPalette.Extensions.Toolkit;
public enum MatchLanguage
{
English,
// CJK will be matched by the CJK language pack
Chinese,
Japanese,
Korean,
}

View File

@@ -22,4 +22,6 @@ public partial class MatchOption
public string Suffix { get; set; } = string.Empty;
public bool IgnoreCase { get; set; } = true;
public MatchLanguage Language { get; set; } = MatchLanguage.English;
}

View File

@@ -38,6 +38,16 @@ public partial class StringMatcher
return Instance.FuzzyMatch(query, stringToCompare);
}
public static MatchResult FuzzySearch(string query, string stringToCompare, MatchLanguage language)
{
var opt = new MatchOption
{
Language = language,
};
return Instance.FuzzyMatch(query, stringToCompare, opt);
}
public MatchResult FuzzyMatch(string query, string stringToCompare)
{
try