mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-06 12:27:01 +01:00
Compare commits
1 Commits
de/vanzue/
...
yuleng/cmd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cf6b03511 |
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; } = [];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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=}">
|
||||
<ToggleSwitch IsOn="{x:Bind viewModel.IsPinYinInput, Mode=TwoWay}" />
|
||||
</controls:SettingsCard>
|
||||
|
||||
<!-- Example 'About' section -->
|
||||
<TextBlock x:Uid="AboutSettingsHeader" Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" />
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(";"))
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user