mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Append Result for everything error and windows index error
This commit is contained in:
parent
786e9427d9
commit
9267938018
13 changed files with 144 additions and 120 deletions
|
|
@ -1,5 +1,10 @@
|
|||
using System;
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Exceptions;
|
||||
|
||||
|
|
@ -7,14 +12,24 @@ public class EngineNotAvailableException : Exception
|
|||
{
|
||||
public string EngineName { get; }
|
||||
public string Resolution { get; }
|
||||
public Func<ActionContext, ValueTask<bool>>? Action { get; }
|
||||
|
||||
public string? ErrorIcon { get; init; }
|
||||
|
||||
public EngineNotAvailableException(string engineName,
|
||||
string resolution,
|
||||
string message) : base(message)
|
||||
string message,
|
||||
Func<ActionContext, ValueTask<bool>> action = null) : base(message)
|
||||
{
|
||||
EngineName = engineName;
|
||||
Resolution = resolution;
|
||||
Action = action ?? (_ =>
|
||||
{
|
||||
Clipboard.SetDataObject(this.ToString());
|
||||
return ValueTask.FromResult(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public EngineNotAvailableException(string engineName,
|
||||
string resolution,
|
||||
string message,
|
||||
|
|
|
|||
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/error.png
Normal file
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3 KiB |
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error.png
Normal file
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error2.png
Normal file
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/robot_error.png
Normal file
BIN
Plugins/Flow.Launcher.Plugin.Explorer/Images/robot_error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -81,25 +81,28 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
try
|
||||
{
|
||||
return await searchManager.SearchAsync(query, token);
|
||||
|
||||
}
|
||||
catch (Exception e) when (e is SearchException or SearchException)
|
||||
catch (Exception e) when (e is SearchException or EngineNotAvailableException)
|
||||
{
|
||||
return new List<Result>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Title = e.Message,
|
||||
SubTitle = e is EngineNotAvailableException engineException
|
||||
? engineException.Resolution
|
||||
SubTitle = e is EngineNotAvailableException { Resolution: { } resolution }
|
||||
? resolution
|
||||
: "Enter to copy the message to clipboard",
|
||||
Score = 501,
|
||||
IcoPath = Constants.ExplorerIconImagePath,
|
||||
Action = _ =>
|
||||
{
|
||||
Clipboard.SetDataObject(e.ToString());
|
||||
return true;
|
||||
}
|
||||
IcoPath = e is EngineNotAvailableException { ErrorIcon: { } iconPath }
|
||||
? iconPath
|
||||
: Constants.GeneralSearchErrorImagePath,
|
||||
AsyncAction = e is EngineNotAvailableException {Action: { } action}
|
||||
? action
|
||||
: _ =>
|
||||
{
|
||||
Clipboard.SetDataObject(e.ToString());
|
||||
return new ValueTask<bool>(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
internal const string QuickAccessImagePath = "Images\\quickaccess.png";
|
||||
internal const string RemoveQuickAccessImagePath = "Images\\removequickaccess.png";
|
||||
internal const string ShowContextMenuImagePath = "Images\\contextmenu.png";
|
||||
internal const string EverythingErrorImagePath = "Images\\everything_error.png";
|
||||
internal const string IndexSearchWarningImagePath = "Images\\index_error.png";
|
||||
internal const string WindowsIndexErrorImagePath = "Images\\index_error2.png";
|
||||
internal const string GeneralSearchErrorImagePath = "Images\\robot_error.png";
|
||||
|
||||
|
||||
internal const string ToolTipOpenDirectory = "Ctrl + Enter to open the directory";
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms.Design;
|
||||
using Flow.Launcher.Plugin.Explorer.Exceptions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
||||
{
|
||||
|
|
@ -87,6 +89,15 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
|||
return fastSortOptionEnabled;
|
||||
}
|
||||
|
||||
public static async ValueTask<bool> IsEverythingRunningAsync(CancellationToken token = default)
|
||||
{
|
||||
await _semaphore.WaitAsync(token);
|
||||
EverythingApiDllImport.Everything_GetMajorVersion();
|
||||
var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError;
|
||||
_semaphore.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the specified key word and reset the everything API afterwards
|
||||
/// </summary>
|
||||
|
|
@ -101,21 +112,21 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
|||
|
||||
if (option.MaxCount < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0");
|
||||
|
||||
|
||||
await _semaphore.WaitAsync(token);
|
||||
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
yield break;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (option.Keyword.StartsWith("@"))
|
||||
{
|
||||
EverythingApiDllImport.Everything_SetRegex(true);
|
||||
option.Keyword = option.Keyword[1..];
|
||||
}
|
||||
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append(option.Keyword);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
|||
|
||||
[DllImport(DLL)]
|
||||
internal static extern int Everything_GetNumFileResults();
|
||||
|
||||
|
||||
[DllImport(DLL)]
|
||||
internal static extern int Everything_GetMajorVersion();
|
||||
|
||||
[DllImport(DLL)]
|
||||
internal static extern int Everything_GetNumFolderResults();
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Search.Everything;
|
||||
|
||||
public class EverythingDownloadHelper
|
||||
public static class EverythingDownloadHelper
|
||||
{
|
||||
public static async Task<string> PromptDownloadIfNotInstallAsync(string installedLocation, IPublicAPI api)
|
||||
{
|
||||
|
|
@ -21,15 +21,17 @@ public class EverythingDownloadHelper
|
|||
|
||||
installedLocation = GetInstalledPath();
|
||||
|
||||
if (string.IsNullOrEmpty(installedLocation) &&
|
||||
System.Windows.Forms.MessageBox.Show(
|
||||
string.Format(api.GetTranslation("flowlauncher_plugin_everything_installing_select"), Environment.NewLine),
|
||||
api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
|
||||
System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
|
||||
if (string.IsNullOrEmpty(installedLocation))
|
||||
{
|
||||
// Solves single thread apartment (STA) mode requirement error when using OpenFileDialog
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
if (System.Windows.Forms.MessageBox.Show(
|
||||
string.Format(api.GetTranslation("flowlauncher_plugin_everything_installing_select"), Environment.NewLine),
|
||||
api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
|
||||
System.Windows.Forms.MessageBoxButtons.YesNo) != System.Windows.Forms.DialogResult.Yes)
|
||||
return;
|
||||
|
||||
var dlg = new System.Windows.Forms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
|
||||
|
|
@ -51,7 +53,7 @@ public class EverythingDownloadHelper
|
|||
{
|
||||
return installedLocation;
|
||||
}
|
||||
|
||||
|
||||
api.ShowMsg(api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
|
||||
api.GetTranslation("flowlauncher_plugin_everything_installing_subtitle"), "", useMainWindowAsOwner: false);
|
||||
|
||||
|
|
@ -96,4 +98,4 @@ public class EverythingDownloadHelper
|
|||
return File.Exists(scoopInstalledPath) ? scoopInstalledPath : string.Empty;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
using System;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Plugin.Explorer.Exceptions;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
||||
|
|
@ -17,37 +22,85 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
|
|||
Settings = settings;
|
||||
}
|
||||
|
||||
|
||||
public IAsyncEnumerable<SearchResult> SearchAsync(string search, CancellationToken token)
|
||||
private async ValueTask ThrowIfEverythingNotAvailableAsync(CancellationToken token = default)
|
||||
{
|
||||
return EverythingApi.SearchAsync(
|
||||
new EverythingSearchOption(search, Settings.SortOption),
|
||||
token);
|
||||
if (!await EverythingApi.IsEverythingRunningAsync(token))
|
||||
throw new EngineNotAvailableException(
|
||||
Enum.GetName(Settings.IndexSearchEngineOption.Everything),
|
||||
"Click to Open or Download Everything",
|
||||
"Everything is not running.",
|
||||
async _ =>
|
||||
{
|
||||
var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(Settings.EverythingInstalledPath, Main.Context.API);
|
||||
if (installedPath == null)
|
||||
{
|
||||
Main.Context.API.ShowMsgError("Unable to find Everything.exe");
|
||||
return false;
|
||||
}
|
||||
Settings.EverythingInstalledPath = installedPath;
|
||||
Process.Start(installedPath, "-startup");
|
||||
return true;
|
||||
})
|
||||
{
|
||||
ErrorIcon = Constants.EverythingErrorImagePath
|
||||
};
|
||||
}
|
||||
public IAsyncEnumerable<SearchResult> ContentSearchAsync(string plainSearch,
|
||||
string contentSearch, CancellationToken token)
|
||||
|
||||
public async IAsyncEnumerable<SearchResult> SearchAsync(string search, [EnumeratorCancellation] CancellationToken token)
|
||||
{
|
||||
await ThrowIfEverythingNotAvailableAsync(token);
|
||||
if (token.IsCancellationRequested)
|
||||
yield break;
|
||||
var option = new EverythingSearchOption(search, Settings.SortOption);
|
||||
await foreach (var result in EverythingApi.SearchAsync(option, token))
|
||||
yield return result;
|
||||
}
|
||||
public async IAsyncEnumerable<SearchResult> ContentSearchAsync(string plainSearch,
|
||||
string contentSearch, [EnumeratorCancellation] CancellationToken token)
|
||||
{
|
||||
await ThrowIfEverythingNotAvailableAsync(token);
|
||||
if (!Settings.EnableEverythingContentSearch)
|
||||
{
|
||||
return AsyncEnumerable.Empty<SearchResult>();
|
||||
throw new EngineNotAvailableException(Enum.GetName(Settings.IndexSearchEngineOption.Everything),
|
||||
"Click to Enable Everything Content Search (only applicable to Everything 1.5+ with indexed content)",
|
||||
"Everything Content Search is not enabled.",
|
||||
_ =>
|
||||
{
|
||||
Settings.EnableEverythingContentSearch = true;
|
||||
return ValueTask.FromResult(true);
|
||||
})
|
||||
{
|
||||
ErrorIcon = Constants.EverythingErrorImagePath
|
||||
};
|
||||
}
|
||||
if (token.IsCancellationRequested)
|
||||
yield break;
|
||||
|
||||
return EverythingApi.SearchAsync(
|
||||
new EverythingSearchOption(
|
||||
plainSearch,
|
||||
Settings.SortOption,
|
||||
true,
|
||||
contentSearch),
|
||||
token);
|
||||
var option = new EverythingSearchOption(plainSearch,
|
||||
Settings.SortOption,
|
||||
true,
|
||||
contentSearch);
|
||||
|
||||
await foreach (var result in EverythingApi.SearchAsync(option, token))
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
public IAsyncEnumerable<SearchResult> EnumerateAsync(string path, string search, bool recursive, CancellationToken token)
|
||||
public async IAsyncEnumerable<SearchResult> EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token)
|
||||
{
|
||||
return EverythingApi.SearchAsync(
|
||||
new EverythingSearchOption(search,
|
||||
Settings.SortOption,
|
||||
ParentPath: path,
|
||||
IsRecursive: recursive),
|
||||
token);
|
||||
await ThrowIfEverythingNotAvailableAsync(token);
|
||||
if (token.IsCancellationRequested)
|
||||
yield break;
|
||||
|
||||
var option = new EverythingSearchOption(search,
|
||||
Settings.SortOption,
|
||||
ParentPath: path,
|
||||
IsRecursive: recursive);
|
||||
|
||||
await foreach (var result in EverythingApi.SearchAsync(option, token))
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
|
||||
using Microsoft.Search.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -10,7 +9,6 @@ using System.Runtime.InteropServices;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Flow.Launcher.Plugin.Explorer.Exceptions;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
||||
|
|
@ -96,21 +94,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
throw new EngineNotAvailableException("Windows Index",
|
||||
api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
|
||||
api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
|
||||
e);
|
||||
e)
|
||||
{
|
||||
ErrorIcon = Constants.WindowsIndexErrorImagePath
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move to General Search Manager
|
||||
private static void RemoveResultsInExclusionList(List<SearchResult> results, IReadOnlyList<AccessLink> exclusionList, CancellationToken token)
|
||||
{
|
||||
var indexExclusionListCount = exclusionList.Count;
|
||||
|
||||
if (indexExclusionListCount == 0)
|
||||
return;
|
||||
results.RemoveAll(searchResult =>
|
||||
exclusionList.Any(exclude => searchResult.FullPath.StartsWith(exclude.Path, StringComparison.OrdinalIgnoreCase))
|
||||
);
|
||||
}
|
||||
|
||||
internal static bool PathIsIndexed(string path)
|
||||
{
|
||||
|
|
@ -127,63 +117,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Use a custom exception to handle this
|
||||
private static List<Result> ResultForWindexSearchOff(string rawQuery)
|
||||
{
|
||||
var api = SearchManager.Context.API;
|
||||
|
||||
return new List<Result>
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
|
||||
SubTitle = api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
|
||||
Action = c =>
|
||||
{
|
||||
SearchManager.Settings.WarnWindowsSearchServiceOff = false;
|
||||
|
||||
var pluginsManagerPlugin = api.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == "9f8f9b14-2518-4907-b211-35ab6290dee7");
|
||||
|
||||
var actionKeywordCount = pluginsManagerPlugin.Metadata.ActionKeywords.Count;
|
||||
|
||||
if (actionKeywordCount > 1)
|
||||
LogException("PluginsManager's action keyword has increased to more than 1, this does not allow for determining the " +
|
||||
"right action keyword. Explorer's code for managing Windows Search service not running exception needs to be updated",
|
||||
new InvalidOperationException());
|
||||
|
||||
if (MessageBox.Show(string.Format(api.GetTranslation("plugin_explorer_alternative"), Environment.NewLine),
|
||||
api.GetTranslation("plugin_explorer_alternative_title"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes
|
||||
&& actionKeywordCount == 1)
|
||||
{
|
||||
api.ChangeQuery($"{pluginsManagerPlugin.Metadata.ActionKeywords[0]} install everything");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clears the warning message because same query string will not alter the displayed result list
|
||||
api.ChangeQuery(string.Empty);
|
||||
|
||||
api.ChangeQuery(rawQuery);
|
||||
}
|
||||
|
||||
var mainWindow = Application.Current.MainWindow!;
|
||||
mainWindow.Show();
|
||||
mainWindow.Focus();
|
||||
|
||||
return false;
|
||||
},
|
||||
IcoPath = Constants.ExplorerIconImagePath
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void LogException(string message, Exception e)
|
||||
{
|
||||
#if DEBUG // Please investigate and handle error from index search
|
||||
throw e;
|
||||
#else
|
||||
Log.Exception($"|Flow.Launcher.Plugin.Explorer.IndexSearch|{message}", e);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue