Compare commits

...

9 Commits

Author SHA1 Message Date
Mike Griese
9dd6b5c350 i broke, pls help 2025-03-25 16:19:16 -05:00
Mike Griese
e4c3b16db2 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:36:00 -05:00
Mike Griese
652715a06d Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:56 -05:00
Mike Griese
0e3965e6c5 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:54 -05:00
Mike Griese
bddaba4a21 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:52 -05:00
Mike Griese
b8d4e4f32a Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:50 -05:00
Mike Griese
16616a6494 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:49 -05:00
Mike Griese
5ae18fb941 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:47 -05:00
Mike Griese
b821bdf8a4 Merge dev/jaime/fix-calc-and-command-fallback-icons 2025-03-25 15:35:32 -05:00
13 changed files with 123 additions and 57 deletions

View File

@@ -141,6 +141,7 @@ public sealed partial class SaveCommand : InvokableCommand
internal sealed partial class FallbackCalculatorItem : FallbackCommandItem
{
private readonly CopyTextCommand _copyCommand = new(string.Empty);
private static readonly IconInfo _cachedIcon = IconHelpers.FromRelativePath("Assets\\Calculator.svg");
public FallbackCalculatorItem()
: base(new NoOpCommand(), Resources.calculator_title)
@@ -149,7 +150,7 @@ internal sealed partial class FallbackCalculatorItem : FallbackCommandItem
_copyCommand.Name = string.Empty;
Title = string.Empty;
Subtitle = Resources.calculator_placeholder_text;
Icon = new IconInfo("\ue8ef"); // Calculator
Icon = _cachedIcon;
}
public override void UpdateQuery(string query)

View File

@@ -13,6 +13,7 @@ using Microsoft.CmdPal.Ext.WindowsServices.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Win32;
using Windows.System;
namespace Microsoft.CmdPal.Ext.WindowsServices.Helpers;
@@ -53,7 +54,10 @@ public static class ServiceHelper
serviceCommand = new ServiceCommand(serviceResult, Action.Stop);
moreCommands = [
new CommandContextItem(new RestartServiceCommand(serviceResult)),
new CommandContextItem(new OpenServicesCommand(serviceResult)),
new CommandContextItem(new OpenServicesCommand(serviceResult))
{
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.O, 0),
},
];
}
else

View File

@@ -127,7 +127,7 @@
<value>Name</value>
</data>
<data name="wox_plugin_service_open_services" xml:space="preserve">
<value>Open services (Ctrl+O)</value>
<value>Open services</value>
</data>
<data name="wox_plugin_service_paused" xml:space="preserve">
<value>Paused</value>
@@ -142,7 +142,7 @@
<value>Service</value>
</data>
<data name="wox_plugin_service_restart" xml:space="preserve">
<value>Restart (Ctrl+R)</value>
<value>Restart</value>
</data>
<data name="wox_plugin_service_restarted_notification" xml:space="preserve">
<value>The service has been restarted</value>

View File

@@ -2,6 +2,7 @@
// 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.Collections.Immutable;
using System.Collections.Specialized;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Ext.Apps;
@@ -101,12 +102,7 @@ public partial class MainListPage : DynamicListPage,
var commands = _tlcManager.TopLevelCommands;
lock (commands)
{
// This gets called on a background thread, because ListViewModel
// updates the .SearchText of all extensions on a BG thread.
foreach (var command in commands)
{
command.TryUpdateFallbackText(newSearch);
}
UpdateFallbacks(newSearch, commands.ToImmutableArray());
// Cleared out the filter text? easy. Reset _filteredItems, and bail out.
if (string.IsNullOrEmpty(newSearch))
@@ -137,6 +133,26 @@ public partial class MainListPage : DynamicListPage,
}
}
private void UpdateFallbacks(string newSearch, IReadOnlyList<TopLevelViewModel> commands)
{
// fire and forget
_ = Task.Run(() =>
{
var needsToUpdate = false;
foreach (var command in commands)
{
var changedVisibility = command.SafeUpdateFallbackTextSynchronous(newSearch);
needsToUpdate = needsToUpdate || changedVisibility;
}
if (needsToUpdate)
{
RaiseItemsChanged();
}
});
}
private bool ActuallyLoading()
{
var tlcManager = _serviceProvider.GetService<TopLevelCommandManager>()!;
@@ -149,17 +165,14 @@ public partial class MainListPage : DynamicListPage,
// _always_ show up first.
private int ScoreTopLevelItem(string query, IListItem topLevelOrAppItem)
{
if (string.IsNullOrWhiteSpace(query))
{
return 1;
}
var title = topLevelOrAppItem.Title;
if (string.IsNullOrEmpty(title))
if (string.IsNullOrWhiteSpace(title))
{
return 0;
}
var isWhiteSpace = string.IsNullOrWhiteSpace(query);
var isFallback = false;
var isAliasSubstringMatch = false;
var isAliasMatch = false;
@@ -179,17 +192,45 @@ public partial class MainListPage : DynamicListPage,
extensionDisplayName = topLevel.ExtensionHost?.Extension?.PackageDisplayName ?? string.Empty;
}
var nameMatch = StringMatcher.FuzzySearch(query, title);
var descriptionMatch = StringMatcher.FuzzySearch(query, topLevelOrAppItem.Subtitle);
var extensionTitleMatch = StringMatcher.FuzzySearch(query, extensionDisplayName);
// StringMatcher.FuzzySearch will absolutely BEEF IT if you give it a
// whitespace-only query.
//
// in that scenario, we'll just use a simple string contains for the
// query. Maybe someone is really looking for things with a space in
// them, I don't know.
// Title:
// * whitespace query: 1 point
// * otherwise full weight match
var nameMatch = isWhiteSpace ?
(title.Contains(query) ? 1 : 0) :
StringMatcher.FuzzySearch(query, title).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;
// 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 scores = new[]
{
nameMatch.Score,
(descriptionMatch.Score - 4) / 2.0,
nameMatch,
descriptionMatch,
isFallback ? 1 : 0, // Always give fallbacks a chance...
};
var max = scores.Max();
max = max + (extensionTitleMatch.Score / 1.5);
// _Add_ the extension name. This will bubble items that match both
// title and extension name up above ones that just match title.
// e.g. "git" will up-weight "GitHub searches" from the GitHub extension
// above "git" from "whatever"
max = max + extensionTitleMatch;
// ... but downweight them
var matchSomething = (max / (isFallback ? 3 : 1))

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using ManagedCommon;
using Microsoft.CmdPal.Common.Services;
using Microsoft.CommandPalette.Extensions;
using Windows.ApplicationModel;
@@ -48,6 +49,7 @@ public class ExtensionService : IExtensionService, IDisposable
{
if (args.IsComplete)
{
Logger.LogDebug($"{args.Package.DisplayName} completed installing");
lock (_lock)
{
InstallPackageUnderLock(args.Package);
@@ -59,6 +61,7 @@ public class ExtensionService : IExtensionService, IDisposable
{
if (args.IsComplete)
{
Logger.LogDebug($"{args.Package.DisplayName} completed uninstalling");
lock (_lock)
{
UninstallPackageUnderLock(args.Package);
@@ -70,6 +73,7 @@ public class ExtensionService : IExtensionService, IDisposable
{
if (args.IsComplete)
{
Logger.LogDebug($"{args.TargetPackage.DisplayName} completed updating");
lock (_lock)
{
// Get any extension providers that we previously had from this app

View File

@@ -2,6 +2,7 @@
// 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.Collections.Immutable;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -209,7 +210,7 @@ public partial class TopLevelCommandManager : ObservableObject,
extensionService.OnExtensionAdded -= ExtensionService_OnExtensionAdded;
extensionService.OnExtensionRemoved -= ExtensionService_OnExtensionRemoved;
var extensions = await extensionService.GetInstalledExtensionsAsync();
var extensions = (await extensionService.GetInstalledExtensionsAsync()).ToImmutableList();
_extensionCommandProviders.Clear();
if (extensions != null)
{
@@ -241,6 +242,7 @@ public partial class TopLevelCommandManager : ObservableObject,
// TODO This most definitely needs a lock
foreach (var extension in extensions)
{
Logger.LogDebug($"Starting {extension.PackageFullName}");
try
{
// start it ...

View File

@@ -4,8 +4,7 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using ManagedCommon;
using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -237,32 +236,46 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
}
}
public void TryUpdateFallbackText(string newQuery)
internal bool SafeUpdateFallbackTextSynchronous(string newQuery)
{
if (!IsFallback)
{
return;
return false;
}
_ = Task.Run(() =>
try
{
try
{
var model = _commandItemViewModel.Model.Unsafe;
if (model is IFallbackCommandItem fallback)
{
var wasEmpty = string.IsNullOrEmpty(Title);
fallback.FallbackHandler.UpdateQuery(newQuery);
var isEmpty = string.IsNullOrEmpty(Title);
if (wasEmpty != isEmpty)
{
WeakReferenceMessenger.Default.Send<UpdateFallbackItemsMessage>();
}
}
}
catch (Exception)
{
}
});
return UnsafeUpdateFallbackSynchronous(newQuery);
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
}
return false;
}
/// <summary>
/// Calls UpdateQuery on our command, if we're a fallback item. This does
/// RPC work, so make sure you're calling it on a BG thread.
/// </summary>
/// <param name="newQuery">The new search text to pass to the extension</param>
/// <returns>true if our Title changed across this call</returns>
private bool UnsafeUpdateFallbackSynchronous(string newQuery)
{
var model = _commandItemViewModel.Model.Unsafe;
// RPC to check type
if (model is IFallbackCommandItem fallback)
{
var wasEmpty = string.IsNullOrEmpty(Title);
// RPC for method
fallback.FallbackHandler.UpdateQuery(newQuery);
var isEmpty = string.IsNullOrEmpty(Title);
return wasEmpty != isEmpty;
}
return false;
}
}

View File

@@ -53,14 +53,14 @@
Grid.Column="1"
VerticalAlignment="Center"
Text="{x:Bind Title, Mode=OneWay}" />
<TextBlock
<!--<TextBlock
Grid.Column="2"
Margin="16,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="{ThemeResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />-->
</Grid>
</DataTemplate>

View File

@@ -66,7 +66,7 @@
<uap5:Extension Category="windows.startupTask">
<uap5:StartupTask
TaskId="CmdPalStartup"
Enabled="true"
Enabled="false"
DisplayName="ms-resource:StartupTaskNameDev" />
</uap5:Extension>

View File

@@ -66,7 +66,7 @@
<uap5:Extension Category="windows.startupTask">
<uap5:StartupTask
TaskId="CmdPalStartup"
Enabled="true"
Enabled="false"
DisplayName="ms-resource:StartupTaskName" />
</uap5:Extension>
@@ -78,5 +78,6 @@
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
<rescap:Capability Name="appLicensing" />
</Capabilities>
</Package>

View File

@@ -42,12 +42,8 @@ public sealed partial class SettingsWindow : Window,
private void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
var selectedItem = args.InvokedItem;
if (selectedItem is not null)
{
Navigate(selectedItem.ToString()!);
}
var selectedItem = args.InvokedItemContainer;
Navigate((selectedItem.Tag as string)!);
}
private void Navigate(string page)

View File

@@ -20,7 +20,7 @@ internal sealed partial class FallbackExecuteItem : FallbackCommandItem
Title = string.Empty;
_executeItem.Name = string.Empty;
Subtitle = Properties.Resources.generic_run_command;
Icon = new IconInfo("\uE756");
Icon = Icons.RunV2; // Defined in Icons.cs and contains the execute command icon.
}
public override void UpdateQuery(string query)

View File

@@ -7,6 +7,7 @@ using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Management.Deployment;
@@ -129,6 +130,9 @@ public partial class InstallPackageCommand : InvokableCommand
WinGetExtensionHost.Instance.HideStatus(_installBanner);
}
});
Logger.LogDebug($"Finished install action for {_package.Name}");
InstallStateChanged?.Invoke(this, this);
}
catch (Exception ex)