Append Result for everything error and windows index error

This commit is contained in:
Hongtao Zhang 2022-11-25 13:25:12 -06:00
parent 786e9427d9
commit 9267938018
No known key found for this signature in database
GPG key ID: 75F655B91C7AC9BB
13 changed files with 144 additions and 120 deletions

View file

@ -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,

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -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);
}
}
};
}

View file

@ -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";

View file

@ -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);

View file

@ -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();

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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
}
}
}