Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<system:String x:Key="plugin_explorer_add">Add</system:String>
<system:String x:Key="plugin_explorer_generalsetting_header">General Setting</system:String>
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Customise Action Keywords</system:String>
<system:String x:Key="plugin_explorer_exclude_quickaccess_from_actionkeywords">Exclude Quick Access results when using action keywords</system:String>
<system:String x:Key="plugin_explorer_manage_quick_access_links_header">Customise Quick Access</system:String>
<system:String x:Key="plugin_explorer_quickaccesslinks_header">Quick Access Links</system:String>
<system:String x:Key="plugin_explorer_everything_setting_header">Everything Setting</system:String>
Expand All @@ -58,6 +59,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Done</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>
Expand Down
134 changes: 71 additions & 63 deletions Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using Flow.Launcher.Plugin.SharedCommands;
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Flow.Launcher.Plugin.Explorer.Exceptions;
using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using Flow.Launcher.Plugin.SharedCommands;
using static Flow.Launcher.Plugin.Explorer.Settings;
using Path = System.IO.Path;

namespace Flow.Launcher.Plugin.Explorer.Search
Expand All @@ -24,6 +27,7 @@ public SearchManager(Settings settings, PluginInitContext context)
Settings = settings;
}


/// <summary>
/// Note: A path that ends with "\" and one that doesn't will not be regarded as equal.
/// </summary>
Expand All @@ -47,79 +51,71 @@ public int GetHashCode(Result obj)
internal async Task<List<Result>> SearchAsync(Query query, CancellationToken token)
{
var results = new HashSet<Result>(PathEqualityComparator.Instance);
var keywordStr = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword;
bool isPathSearch = query.Search.IsLocationPathString()
|| EnvironmentVariables.IsEnvironmentVariableSearch(query.Search)
|| EnvironmentVariables.HasEnvironmentVar(query.Search);

// This allows the user to type the below action keywords and see/search the list of quick folder links
if (ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword))
var activeActionKeyword = Settings.GetActiveActionKeyword(keywordStr);

if (activeActionKeyword == null && !isPathSearch)
{
if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword))
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
return new List<Result>();
}
else

if (activeActionKeyword == null && isPathSearch) activeActionKeyword = ActionKeyword.PathSearchActionKeyword;

// This allows the user to type the below action keywords and see/search the list of quick folder links

if (string.IsNullOrEmpty(query.Search)
&& activeActionKeyword!.Equals(ActionKeyword.QuickAccessActionKeyword))
{
// No action keyword matched- plugin should not handle this query, return empty results.
return new List<Result>();
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
}

IAsyncEnumerable<SearchResult> searchResults;

bool isPathSearch = query.Search.IsLocationPathString()
|| EnvironmentVariables.IsEnvironmentVariableSearch(query.Search)
|| EnvironmentVariables.HasEnvironmentVar(query.Search);

string engineName;

switch (isPathSearch)
switch (activeActionKeyword!.Equals(ActionKeyword.PathSearchActionKeyword))
{
case true
when ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):

case true:
results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));

return results.ToList();

case false
when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword):

// Intentionally require enabling of Everything's content search due to its slowness
when activeActionKeyword.Equals(ActionKeyword.FileContentSearchActionKeyword):
if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch)
return EverythingContentSearchResult(query);

searchResults = Settings.ContentIndexProvider.ContentSearchAsync("", query.Search, token);
engineName = Enum.GetName(Settings.ContentSearchEngine);
break;

case false
when ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):
case false
when activeActionKeyword.Equals(ActionKeyword.QuickAccessActionKeyword):
return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);


default:
searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
engineName = Enum.GetName(Settings.IndexSearchEngine);
break;

case true or false
when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);

default:
return results.ToList();
}

// Merge Quick Access Link results for non-path searches.
results.UnionWith(QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks));

MergeQuickAccessInResultsIfQueryMatch(results, query, activeActionKeyword);
try
{
await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false))
if (search.Type == ResultType.File && IsExcludedFile(search)) {
{
if (ShouldSkip(activeActionKeyword!.Value, search))
{
continue;
} else {
results.Add(ResultManager.CreateResult(query, search));
}
results.Add(ResultManager.CreateResult(query, search));

}
}
catch (OperationCanceledException)
{
Expand All @@ -140,25 +136,6 @@ when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
return results.ToList();
}

private bool ActionKeywordMatch(Query query, Settings.ActionKeyword allowedActionKeyword)
{
var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword;

return allowedActionKeyword switch
{
Settings.ActionKeyword.SearchActionKeyword => Settings.SearchActionKeywordEnabled &&
keyword == Settings.SearchActionKeyword,
Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled &&
keyword == Settings.PathSearchActionKeyword,
Settings.ActionKeyword.FileContentSearchActionKeyword => Settings.FileContentSearchKeywordEnabled &&
keyword == Settings.FileContentSearchActionKeyword,
Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexSearchKeywordEnabled &&
keyword == Settings.IndexSearchActionKeyword,
Settings.ActionKeyword.QuickAccessActionKeyword => Settings.QuickAccessKeywordEnabled &&
keyword == Settings.QuickAccessActionKeyword,
_ => throw new ArgumentOutOfRangeException(nameof(allowedActionKeyword), allowedActionKeyword, "actionKeyword out of range")
};
}

private List<Result> EverythingContentSearchResult(Query query)
{
Expand Down Expand Up @@ -280,5 +257,36 @@ private bool IsExcludedFile(SearchResult result)

return excludedFileTypes.Contains(fileExtension, StringComparer.OrdinalIgnoreCase);
}

private bool ShouldSkip(ActionKeyword actionKeywordActive, SearchResult search)
{
if (search.Type == ResultType.File && IsExcludedFile(search))
return true;

if (actionKeywordActive.Equals(ActionKeyword.FolderSearchActionKeyword)
&& search.Type != ResultType.Folder)
{
return true;
}

if (actionKeywordActive.Equals(ActionKeyword.FileSearchActionKeyword)
&& search.Type != ResultType.File)
{
return true;
}

return false;
}

private void MergeQuickAccessInResultsIfQueryMatch(HashSet<Result> results, Query query, ActionKeyword? activeActionKeyword)
{
if (activeActionKeyword != null && activeActionKeyword != ActionKeyword.QuickAccessActionKeyword)
{
if (Settings.ExcludeQuickAccessFromActionKeywords) return;
}
var quickAccessMatched = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
if (quickAccessMatched != null && quickAccessMatched.Count > 0) results.UnionWith(quickAccessMatched);
}
}

}
51 changes: 44 additions & 7 deletions Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.Json.Serialization;
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;

namespace Flow.Launcher.Plugin.Explorer
{
Expand Down Expand Up @@ -58,6 +59,17 @@ public class Settings

public bool QuickAccessKeywordEnabled { get; set; }


public string FolderSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;

public bool FolderSearchKeywordEnabled { get; set; }

public string FileSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;

public bool FileSearchKeywordEnabled { get; set; }

public bool ExcludeQuickAccessFromActionKeywords { get; set; } = false;

public bool WarnWindowsSearchServiceOff { get; set; } = true;

public bool ShowFileSizeInPreviewPanel { get; set; } = true;
Expand Down Expand Up @@ -154,13 +166,16 @@ public enum ContentIndexSearchEngineOption

#endregion

internal enum ActionKeyword
public enum ActionKeyword
{
SearchActionKeyword,
PathSearchActionKeyword,
FileContentSearchActionKeyword,
IndexSearchActionKeyword,
QuickAccessActionKeyword
QuickAccessActionKeyword,
FolderSearchActionKeyword,
FileSearchActionKeyword,

}

internal string GetActionKeyword(ActionKeyword actionKeyword) => actionKeyword switch
Expand All @@ -170,6 +185,8 @@ internal enum ActionKeyword
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword,
ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword,
ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword,
ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword,
ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found")
};

Expand All @@ -180,6 +197,8 @@ internal enum ActionKeyword
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword = keyword,
ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword = keyword,
ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword = keyword,
ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword = keyword,
ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword = keyword,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found")
};

Expand All @@ -190,6 +209,8 @@ internal enum ActionKeyword
ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled,
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled,
ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled,
ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled,
ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};

Expand All @@ -200,7 +221,23 @@ internal enum ActionKeyword
ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled = enable,
ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled = enable,
ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled = enable,
ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled = enable,
ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled = enable,
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};

public ActionKeyword? GetActiveActionKeyword(string actionKeywordStr)
{
if (string.IsNullOrEmpty(actionKeywordStr)) return null;
foreach (ActionKeyword action in Enum.GetValues(typeof(ActionKeyword)))
{
var keywordStr = GetActionKeyword(action);
if (string.IsNullOrEmpty(keywordStr)) continue;
var isEnabled = GetActionKeywordEnabled(action);
if (keywordStr == actionKeywordStr && isEnabled) return action;
}
return null;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,17 @@
new(Settings.ActionKeyword.SearchActionKeyword,
"plugin_explorer_actionkeywordview_search"),
new(Settings.ActionKeyword.FileContentSearchActionKeyword,
"plugin_explorer_actionkeywordview_filecontentsearch"),

Check warning on line 276 in Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`actionkeywordview` is not a recognized word. (unrecognized-spelling)
new(Settings.ActionKeyword.PathSearchActionKeyword,
"plugin_explorer_actionkeywordview_pathsearch"),

Check warning on line 278 in Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`actionkeywordview` is not a recognized word. (unrecognized-spelling)
new(Settings.ActionKeyword.IndexSearchActionKeyword,
"plugin_explorer_actionkeywordview_indexsearch"),

Check warning on line 280 in Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`actionkeywordview` is not a recognized word. (unrecognized-spelling)
new(Settings.ActionKeyword.QuickAccessActionKeyword,
"plugin_explorer_actionkeywordview_quickaccess")
"plugin_explorer_actionkeywordview_quickaccess"),

Check warning on line 282 in Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`actionkeywordview` is not a recognized word. (unrecognized-spelling)
new(Settings.ActionKeyword.FolderSearchActionKeyword,
"plugin_explorer_actionkeywordview_foldersearch"),
new(Settings.ActionKeyword.FileSearchActionKeyword,
"plugin_explorer_actionkeywordview_filesearch")
};
}

Expand Down Expand Up @@ -465,7 +469,7 @@

private static string? PromptUserSelectPath(ResultType type, string? initialDirectory = null)
{
string? path = null;
string? path = null;

if (type is ResultType.Folder)
{
Expand Down
16 changes: 13 additions & 3 deletions Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -508,22 +508,22 @@
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
VerticalAlignment="Center"
Foreground="{DynamicResource Color05B}"
Text="{DynamicResource plugin_explorer_previewpanel_file_info_label}" />

Check warning on line 511 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`previewpanel` is not a recognized word. (unrecognized-spelling)
<WrapPanel
Width="Auto"
HorizontalAlignment="Right"
DockPanel.Dock="Right">
<CheckBox
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
Content="{DynamicResource plugin_explorer_previewpanel_display_file_size_checkbox}"

Check warning on line 518 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`previewpanel` is not a recognized word. (unrecognized-spelling)
IsChecked="{Binding ShowFileSizeInPreviewPanel}" />
<CheckBox
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
Content="{DynamicResource plugin_explorer_previewpanel_display_file_creation_checkbox}"

Check warning on line 522 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`previewpanel` is not a recognized word. (unrecognized-spelling)
IsChecked="{Binding ShowCreatedDateInPreviewPanel}" />
<CheckBox
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
Content="{DynamicResource plugin_explorer_previewpanel_display_file_modification_checkbox}"

Check warning on line 526 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`previewpanel` is not a recognized word. (unrecognized-spelling)
IsChecked="{Binding ShowModifiedDateInPreviewPanel}" />
<CheckBox
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
Expand Down Expand Up @@ -674,17 +674,27 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Border
<CheckBox
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
HorizontalAlignment="Left"
Content="{DynamicResource plugin_explorer_exclude_quickaccess_from_actionkeywords}"

Check warning on line 690 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`quickaccess` is not a recognized word. (unrecognized-spelling)
IsChecked="{Binding Settings.ExcludeQuickAccessFromActionKeywords}" />

<Border
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
HorizontalAlignment="Stretch"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="1">
Expand All @@ -695,7 +705,7 @@
</Border>

<StackPanel
Grid.Row="1"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
Expand Down Expand Up @@ -739,7 +749,7 @@
Height="200"
AllowDrop="True"
BorderThickness="1"
DragEnter="lbxAccessLinks_DragEnter"

Check warning on line 752 in Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml

View workflow job for this annotation

GitHub Actions / Check Spelling

`lbx` is not a recognized word. (unrecognized-spelling)
Drop="LbxAccessLinks_OnDrop"
ItemsSource="{Binding Settings.QuickAccessLinks}"
Loaded="lbxAccessLinks_Loaded"
Expand Down
Loading