mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge f10f716619 into 24f6c90f72
This commit is contained in:
commit
1f3b387977
5 changed files with 115 additions and 29 deletions
|
|
@ -30,7 +30,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
private static readonly ConcurrentDictionary<string, PluginPair> _allInitializedPlugins = [];
|
||||
private static readonly ConcurrentDictionary<string, PluginPair> _initFailedPlugins = [];
|
||||
private static readonly ConcurrentDictionary<string, PluginPair> _globalPlugins = [];
|
||||
private static readonly ConcurrentDictionary<string, PluginPair> _nonGlobalPlugins = [];
|
||||
private static readonly ConcurrentDictionary<string, List<PluginPair>> _nonGlobalPlugins = [];
|
||||
|
||||
private static PluginsSettings Settings;
|
||||
private static readonly ConcurrentBag<string> ModifiedPlugins = [];
|
||||
|
|
@ -333,7 +333,19 @@ namespace Flow.Launcher.Core.Plugin
|
|||
_globalPlugins.TryAdd(pair.Metadata.ID, pair);
|
||||
break;
|
||||
default:
|
||||
_nonGlobalPlugins.TryAdd(actionKeyword, pair);
|
||||
_nonGlobalPlugins.AddOrUpdate(actionKeyword,
|
||||
_ => [pair],
|
||||
(_, existing) =>
|
||||
{
|
||||
lock (existing)
|
||||
{
|
||||
if (!existing.Contains(pair))
|
||||
{
|
||||
existing.Add(pair);
|
||||
}
|
||||
}
|
||||
return existing;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -369,7 +381,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
if (query is null)
|
||||
return Array.Empty<PluginPair>();
|
||||
|
||||
if (!_nonGlobalPlugins.TryGetValue(query.ActionKeyword, out var plugin))
|
||||
if (!TryGetNonGlobalPlugins(query.ActionKeyword, out var plugins))
|
||||
{
|
||||
if (dialogJump)
|
||||
return [.. GetGlobalPlugins().Where(p => p.Plugin is IAsyncDialogJump && !PluginModified(p.Metadata.ID))];
|
||||
|
|
@ -377,13 +389,25 @@ namespace Flow.Launcher.Core.Plugin
|
|||
return [.. GetGlobalPlugins().Where(p => !PluginModified(p.Metadata.ID))];
|
||||
}
|
||||
|
||||
if (dialogJump && plugin.Plugin is not IAsyncDialogJump)
|
||||
return Array.Empty<PluginPair>();
|
||||
var validPlugins = plugins.Where(p => !p.Metadata.Disabled && !PluginModified(p.Metadata.ID));
|
||||
if (dialogJump)
|
||||
validPlugins = validPlugins.Where(p => p.Plugin is IAsyncDialogJump);
|
||||
|
||||
if (PluginModified(plugin.Metadata.ID))
|
||||
return Array.Empty<PluginPair>();
|
||||
return [.. validPlugins];
|
||||
}
|
||||
|
||||
return [plugin];
|
||||
private static bool TryGetNonGlobalPlugins(string actionKeyword, out List<PluginPair> plugins)
|
||||
{
|
||||
if (_nonGlobalPlugins.TryGetValue(actionKeyword, out var list))
|
||||
{
|
||||
lock (list)
|
||||
{
|
||||
plugins = [.. list];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
plugins = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ICollection<PluginPair> ValidPluginsForHomeQuery()
|
||||
|
|
@ -577,9 +601,17 @@ namespace Flow.Launcher.Core.Plugin
|
|||
return [.. _globalPlugins.Values];
|
||||
}
|
||||
|
||||
public static Dictionary<string, PluginPair> GetNonGlobalPlugins()
|
||||
public static Dictionary<string, List<PluginPair>> GetNonGlobalPlugins()
|
||||
{
|
||||
return _nonGlobalPlugins.ToDictionary();
|
||||
var nonGlobalPlugins = new Dictionary<string, List<PluginPair>>();
|
||||
foreach (var kvp in _nonGlobalPlugins)
|
||||
{
|
||||
lock (kvp.Value)
|
||||
{
|
||||
nonGlobalPlugins.Add(kvp.Key, [.. kvp.Value]);
|
||||
}
|
||||
}
|
||||
return nonGlobalPlugins;
|
||||
}
|
||||
|
||||
public static List<PluginPair> GetTranslationPlugins()
|
||||
|
|
@ -722,12 +754,12 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
#region Plugin Action Keyword
|
||||
|
||||
[Obsolete("This method is only used for old Flow compatibility.")]
|
||||
public static bool ActionKeywordRegistered(string actionKeyword)
|
||||
{
|
||||
// this method is only checking for action keywords (defined as not '*') registration
|
||||
// hence the actionKeyword != Query.GlobalPluginWildcardSign logic
|
||||
return actionKeyword != Query.GlobalPluginWildcardSign
|
||||
&& _nonGlobalPlugins.ContainsKey(actionKeyword);
|
||||
// Since now we support to assign one action keyword to multiple plugins,
|
||||
// this check is unnecessary, so we will just return false here to ensure compatibility for old plugins.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -737,17 +769,34 @@ namespace Flow.Launcher.Core.Plugin
|
|||
public static void AddActionKeyword(string id, string newActionKeyword)
|
||||
{
|
||||
var plugin = GetPluginForId(id);
|
||||
if (plugin == null) return;
|
||||
|
||||
if (newActionKeyword == Query.GlobalPluginWildcardSign)
|
||||
{
|
||||
_globalPlugins.TryAdd(id, plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
_nonGlobalPlugins.AddOrUpdate(newActionKeyword, plugin, (key, oldValue) => plugin);
|
||||
_nonGlobalPlugins.AddOrUpdate(newActionKeyword,
|
||||
_ => [plugin],
|
||||
(_, existing) =>
|
||||
{
|
||||
lock (existing)
|
||||
{
|
||||
if (!existing.Contains(plugin))
|
||||
{
|
||||
existing.Add(plugin);
|
||||
}
|
||||
}
|
||||
return existing;
|
||||
});
|
||||
}
|
||||
|
||||
// Update action keywords and action keyword in plugin metadata
|
||||
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
|
||||
if (!plugin.Metadata.ActionKeywords.Contains(newActionKeyword))
|
||||
{
|
||||
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
|
||||
}
|
||||
if (plugin.Metadata.ActionKeywords.Count > 0)
|
||||
{
|
||||
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
|
||||
|
|
@ -765,6 +814,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
public static void RemoveActionKeyword(string id, string oldActionkeyword)
|
||||
{
|
||||
var plugin = GetPluginForId(id);
|
||||
if (plugin == null) return;
|
||||
|
||||
if (oldActionkeyword == Query.GlobalPluginWildcardSign
|
||||
&& // Plugins may have multiple ActionKeywords that are global, eg. WebSearch
|
||||
plugin.Metadata.ActionKeywords
|
||||
|
|
@ -775,11 +826,22 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
|
||||
{
|
||||
_nonGlobalPlugins.TryRemove(oldActionkeyword, out _);
|
||||
if (_nonGlobalPlugins.TryGetValue(oldActionkeyword, out var plugins))
|
||||
{
|
||||
lock (plugins)
|
||||
{
|
||||
plugins.RemoveAll(p => p.Metadata.ID == id);
|
||||
|
||||
if (plugins.Count == 0)
|
||||
{
|
||||
_nonGlobalPlugins.TryRemove(new KeyValuePair<string, List<PluginPair>>(oldActionkeyword, plugins));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update action keywords and action keyword in plugin metadata
|
||||
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
|
||||
plugin.Metadata.ActionKeywords.RemoveAll(k => k == oldActionkeyword);
|
||||
if (plugin.Metadata.ActionKeywords.Count > 0)
|
||||
{
|
||||
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
|
||||
|
|
@ -1063,10 +1125,18 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
_globalPlugins.TryRemove(plugin.ID, out var _);
|
||||
}
|
||||
var keysToRemove = _nonGlobalPlugins.Where(p => p.Value.Metadata.ID == plugin.ID).Select(p => p.Key).ToList();
|
||||
foreach (var key in keysToRemove)
|
||||
var entriesToUpdate = _nonGlobalPlugins.ToList();
|
||||
foreach (var entry in entriesToUpdate)
|
||||
{
|
||||
_nonGlobalPlugins.TryRemove(key, out var _);
|
||||
lock (entry.Value)
|
||||
{
|
||||
entry.Value.RemoveAll(p => p.Metadata.ID == plugin.ID);
|
||||
|
||||
if (entry.Value.Count == 0)
|
||||
{
|
||||
_nonGlobalPlugins.TryRemove(new KeyValuePair<string, List<PluginPair>>(entry.Key, entry.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
public static class QueryBuilder
|
||||
{
|
||||
public static Query Build(string originalQuery, string trimmedQuery, Dictionary<string, PluginPair> nonGlobalPlugins)
|
||||
public static Query Build(string originalQuery, string trimmedQuery, Dictionary<string, List<PluginPair>> nonGlobalPlugins)
|
||||
{
|
||||
// home query
|
||||
if (string.IsNullOrEmpty(trimmedQuery))
|
||||
|
|
@ -34,7 +35,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
string possibleActionKeyword = terms[0];
|
||||
string[] searchTerms;
|
||||
|
||||
if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled)
|
||||
if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPairs) && CheckPlugin(pluginPairs))
|
||||
{
|
||||
// use non global plugin for query
|
||||
actionKeyword = possibleActionKeyword;
|
||||
|
|
@ -59,5 +60,13 @@ namespace Flow.Launcher.Core.Plugin
|
|||
IsHomeQuery = false
|
||||
};
|
||||
}
|
||||
|
||||
private static bool CheckPlugin(List<PluginPair> pluginPairs)
|
||||
{
|
||||
lock (pluginPairs)
|
||||
{
|
||||
return pluginPairs.Any(plugin => !plugin.Metadata.Disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,6 +293,11 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
/// <param name="actionKeyword">The actionkeyword for checking</param>
|
||||
/// <returns>True if the actionkeyword is already assigned, False otherwise</returns>
|
||||
/// <remarks>
|
||||
/// Flow now supports assigning one action keyword to multiple plugins.
|
||||
/// This method is kept only for legacy Flow compatibility.
|
||||
/// </remarks>
|
||||
[Obsolete("Flow now supports assigning one action keyword to multiple plugins. This method always returns false for compatibility.")]
|
||||
bool ActionKeywordAssigned(string actionKeyword);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ namespace Flow.Launcher.Test
|
|||
[Test]
|
||||
public void ExclusivePluginQueryTest()
|
||||
{
|
||||
var nonGlobalPlugins = new Dictionary<string, PluginPair>
|
||||
var nonGlobalPlugins = new Dictionary<string, List<PluginPair>>
|
||||
{
|
||||
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}}}}
|
||||
{ ">", new List<PluginPair>(){ new() { Metadata = new PluginMetadata { ActionKeywords = [">"] } } } }
|
||||
};
|
||||
|
||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||
|
|
@ -34,9 +34,9 @@ namespace Flow.Launcher.Test
|
|||
[Test]
|
||||
public void ExclusivePluginQueryIgnoreDisabledTest()
|
||||
{
|
||||
var nonGlobalPlugins = new Dictionary<string, PluginPair>
|
||||
var nonGlobalPlugins = new Dictionary<string, List<PluginPair>>
|
||||
{
|
||||
{">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List<string> {">"}, Disabled = true}}}
|
||||
{ ">", new List<PluginPair>(){ new() { Metadata = new PluginMetadata { ActionKeywords = [">"], Disabled = true } } } }
|
||||
};
|
||||
|
||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||
|
|
@ -51,7 +51,7 @@ namespace Flow.Launcher.Test
|
|||
[Test]
|
||||
public void GenericPluginQueryTest()
|
||||
{
|
||||
Query q = QueryBuilder.Build("file.txt file2 file3", "file.txt file2 file3", new Dictionary<string, PluginPair>());
|
||||
Query q = QueryBuilder.Build("file.txt file2 file3", "file.txt file2 file3", []);
|
||||
|
||||
ClassicAssert.AreEqual("file.txt file2 file3", q.Search);
|
||||
ClassicAssert.AreEqual("", q.ActionKeyword);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
|
@ -267,7 +267,9 @@ namespace Flow.Launcher
|
|||
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
|
||||
PluginManager.AddActionKeyword(pluginId, newActionKeyword);
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
public bool ActionKeywordAssigned(string actionKeyword) => PluginManager.ActionKeywordRegistered(actionKeyword);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
public void RemoveActionKeyword(string pluginId, string oldActionKeyword) =>
|
||||
PluginManager.RemoveActionKeyword(pluginId, oldActionKeyword);
|
||||
|
|
|
|||
Loading…
Reference in a new issue