Merge pull request #3261 from Jack251970/multiple_keywords

Support Multiple keywords for Plugins
This commit is contained in:
Jack Ye 2025-03-20 13:46:23 +08:00 committed by GitHub
commit 87f765be4a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 85 additions and 40 deletions

View file

@ -231,7 +231,6 @@ namespace Flow.Launcher.Core.Plugin
if (!NonGlobalPlugins.ContainsKey(query.ActionKeyword))
return GlobalPlugins;
var plugin = NonGlobalPlugins[query.ActionKeyword];
return new List<PluginPair>
{
@ -367,7 +366,16 @@ namespace Flow.Launcher.Core.Plugin
NonGlobalPlugins[newActionKeyword] = plugin;
}
// Update action keywords and action keyword in plugin metadata
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
if (plugin.Metadata.ActionKeywords.Count > 0)
{
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
}
else
{
plugin.Metadata.ActionKeyword = string.Empty;
}
}
/// <summary>
@ -388,16 +396,15 @@ namespace Flow.Launcher.Core.Plugin
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
NonGlobalPlugins.Remove(oldActionkeyword);
// Update action keywords and action keyword in plugin metadata
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
}
public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword)
{
if (oldActionKeyword != newActionKeyword)
if (plugin.Metadata.ActionKeywords.Count > 0)
{
AddActionKeyword(id, newActionKeyword);
RemoveActionKeyword(id, oldActionKeyword);
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
}
else
{
plugin.Metadata.ActionKeyword = string.Empty;
}
}

View file

@ -152,7 +152,6 @@ namespace Flow.Launcher.Plugin
/// <param name="callback"></param>
public void RemoveGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback);
/// <summary>
/// Fuzzy Search the string with the given query. This is the core search mechanism Flow uses
/// </summary>
@ -191,14 +190,15 @@ namespace Flow.Launcher.Plugin
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
/// <summary>
/// Add ActionKeyword for specific plugin
/// Add ActionKeyword and update action keyword metadata for specific plugin
/// Before adding, please check if action keyword is already assigned by <see cref="ActionKeywordAssigned"/>
/// </summary>
/// <param name="pluginId">ID for plugin that needs to add action keyword</param>
/// <param name="newActionKeyword">The actionkeyword that is supposed to be added</param>
void AddActionKeyword(string pluginId, string newActionKeyword);
/// <summary>
/// Remove ActionKeyword for specific plugin
/// Remove ActionKeyword and update action keyword metadata for specific plugin
/// </summary>
/// <param name="pluginId">ID for plugin that needs to remove action keyword</param>
/// <param name="oldActionKeyword">The actionkeyword that is supposed to be removed</param>

View file

@ -34,6 +34,8 @@ namespace Flow.Launcher.Plugin
public List<string> ActionKeywords { get; set; }
public bool HideActionKeywordPanel { get; set; }
public string IcoPath { get; set;}
public override string ToString()

View file

@ -39,10 +39,9 @@ namespace Flow.Launcher.Plugin
public const string TermSeparator = " ";
/// <summary>
/// User can set multiple action keywords seperated by ';'
/// User can set multiple action keywords seperated by whitespace
/// </summary>
public const string ActionKeywordSeparator = ";";
public const string ActionKeywordSeparator = TermSeparator;
/// <summary>
/// Wildcard action keyword. Plugins using this value will be queried on every search.

View file

@ -3,6 +3,8 @@ using Flow.Launcher.Core.Resource;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
using Flow.Launcher.Core;
using System.Linq;
using System.Collections.Generic;
namespace Flow.Launcher
{
@ -32,14 +34,37 @@ namespace Flow.Launcher
private void btnDone_OnClick(object sender, RoutedEventArgs _)
{
var oldActionKeyword = plugin.Metadata.ActionKeywords[0];
var newActionKeyword = tbAction.Text.Trim();
newActionKeyword = newActionKeyword.Length > 0 ? newActionKeyword : "*";
if (!PluginViewModel.IsActionKeywordRegistered(newActionKeyword))
var oldActionKeywords = plugin.Metadata.ActionKeywords;
var newActionKeywords = tbAction.Text.Split(Query.ActionKeywordSeparator).ToList();
newActionKeywords.RemoveAll(string.IsNullOrEmpty);
newActionKeywords = newActionKeywords.Distinct().ToList();
newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign };
var addedActionKeywords = newActionKeywords.Except(oldActionKeywords).ToList();
var removedActionKeywords = oldActionKeywords.Except(newActionKeywords).ToList();
if (!addedActionKeywords.Any(App.API.ActionKeywordAssigned))
{
pluginViewModel.ChangeActionKeyword(newActionKeyword, oldActionKeyword);
Close();
if (oldActionKeywords.Count != newActionKeywords.Count)
{
ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords);
return;
}
var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList();
var sortedNewActionKeywords = newActionKeywords.OrderBy(s => s).ToList();
if (sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords))
{
// User just changes the sequence of action keywords
var msg = translater.GetTranslation("newActionKeywordsSameAsOld");
MessageBoxEx.Show(msg);
}
else
{
ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords);
}
}
else
{
@ -47,5 +72,21 @@ namespace Flow.Launcher
App.API.ShowMsgBox(msg);
}
}
private void ReplaceActionKeyword(string id, IReadOnlyList<string> removedActionKeywords, IReadOnlyList<string> addedActionKeywords)
{
foreach (var actionKeyword in removedActionKeywords)
{
App.API.RemoveActionKeyword(id, actionKeyword);
}
foreach (var actionKeyword in addedActionKeywords)
{
App.API.AddActionKeyword(id, actionKeyword);
}
// Update action keywords text and close window
pluginViewModel.OnActionKeywordsChanged();
Close();
}
}
}

View file

@ -342,9 +342,10 @@
<system:String x:Key="cannotFindSpecifiedPlugin">Can't find specified plugin</system:String>
<system:String x:Key="newActionKeywordsCannotBeEmpty">New Action Keyword can't be empty</system:String>
<system:String x:Key="newActionKeywordsHasBeenAssigned">This new Action Keyword is already assigned to another plugin, please choose a different one</system:String>
<system:String x:Key="newActionKeywordsSameAsOld">This new Action Keyword is the same as old, please choose a different one</system:String>
<system:String x:Key="success">Success</system:String>
<system:String x:Key="completedSuccessfully">Completed successfully</system:String>
<system:String x:Key="actionkeyword_tips">Enter the action keyword you like to use to start the plugin. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords.</system:String>
<system:String x:Key="actionkeyword_tips">Enter the action keywords you like to use to start the plugin and use whitespace to divide them. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords.</system:String>
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>

View file

@ -331,7 +331,6 @@ namespace Flow.Launcher
return _mainVM.GameModeStatus;
}
private readonly List<Func<int, int, SpecialKeyState, bool>> _globalKeyboardHandlers = new();
public void RegisterGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Add(callback);

View file

@ -43,7 +43,6 @@ namespace Flow.Launcher.ViewModel
}
}
private async void LoadIconAsync()
{
Image = await ImageLoader.LoadAsync(PluginPair.Metadata.IcoPath);
@ -100,7 +99,7 @@ namespace Flow.Launcher.ViewModel
: null;
private ImageSource _image = ImageLoader.MissingImage;
public Visibility ActionKeywordsVisibility => PluginPair.Metadata.ActionKeywords.Count == 1 ? Visibility.Visible : Visibility.Collapsed;
public Visibility ActionKeywordsVisibility => PluginPair.Metadata.HideActionKeywordPanel ? Visibility.Collapsed : Visibility.Visible;
public string InitilizaTime => PluginPair.Metadata.InitTime + "ms";
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
public string Version => InternationalizationManager.Instance.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version;
@ -109,9 +108,8 @@ namespace Flow.Launcher.ViewModel
public int Priority => PluginPair.Metadata.Priority;
public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; }
public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword)
public void OnActionKeywordsChanged()
{
PluginManager.ReplaceActionKeyword(PluginPair.Metadata.ID, oldActionKeyword, newActionKeyword);
OnPropertyChanged(nameof(ActionKeywordsText));
}
@ -150,8 +148,6 @@ namespace Flow.Launcher.ViewModel
App.API.ShowMainWindow();
}
public static bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
[RelayCommand]
private void SetActionKeywords()
{

View file

@ -43,6 +43,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -7,6 +7,7 @@
"*",
"*"
],
"HideActionKeywordPanel": true,
"Name": "Explorer",
"Description": "Find and manage files and folders via Windows Search or Everything",
"Author": "Jeremy Wu",

View file

@ -19,7 +19,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
</ItemGroup>

View file

@ -51,7 +51,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
</ItemGroup>

View file

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Windows;
using Microsoft.Win32;
using Flow.Launcher.Core.Plugin;
namespace Flow.Launcher.Plugin.WebSearch
{
@ -16,7 +15,6 @@ namespace Flow.Launcher.Plugin.WebSearch
private SearchSourceViewModel _viewModel;
private string selectedNewIconImageFullPath;
public SearchSourceSettingWindow(IList<SearchSource> sources, PluginInitContext context, SearchSource old)
{
_oldSearchSource = old;
@ -80,10 +78,10 @@ namespace Flow.Launcher.Plugin.WebSearch
private void AddSearchSource()
{
var keyword = _searchSource.ActionKeyword;
if (!PluginManager.ActionKeywordRegistered(keyword))
if (!_context.API.ActionKeywordAssigned(keyword))
{
var id = _context.CurrentPluginMetadata.ID;
PluginManager.AddActionKeyword(id, keyword);
_context.API.AddActionKeyword(id, keyword);
_searchSources.Add(_searchSource);
@ -100,10 +98,11 @@ namespace Flow.Launcher.Plugin.WebSearch
{
var newKeyword = _searchSource.ActionKeyword;
var oldKeyword = _oldSearchSource.ActionKeyword;
if (!PluginManager.ActionKeywordRegistered(newKeyword) || oldKeyword == newKeyword)
if (!_context.API.ActionKeywordAssigned(newKeyword) || oldKeyword == newKeyword)
{
var id = _context.CurrentPluginMetadata.ID;
PluginManager.ReplaceActionKeyword(id, oldKeyword, newKeyword);
_context.API.RemoveActionKeyword(id, oldKeyword);
_context.API.AddActionKeyword(id, newKeyword);
var index = _searchSources.IndexOf(_oldSearchSource);
_searchSources[index] = _searchSource;

View file

@ -1,6 +1,5 @@
using System.Windows;
using System.Windows.Controls;
using Flow.Launcher.Core.Plugin;
using System.ComponentModel;
using System.Windows.Data;
@ -40,7 +39,7 @@ namespace Flow.Launcher.Plugin.WebSearch
if (result == MessageBoxResult.Yes)
{
var id = _context.CurrentPluginMetadata.ID;
PluginManager.RemoveActionKeyword(id, selected.ActionKeyword);
_context.API.RemoveActionKeyword(id, selected.ActionKeyword);
_settings.SearchSources.Remove(selected);
}
}

View file

@ -23,6 +23,7 @@
"yahoo",
"bd"
],
"HideActionKeywordPanel": true,
"Name": "Web Searches",
"Description": "Provide the web search ability",
"Author": "qianlifeng",