Merge pull request #604 from Flow-Launcher/dev

Release 1.8.1
This commit is contained in:
Jeremy Wu 2021-07-29 14:16:29 +10:00 committed by GitHub
commit 620ed4afea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 350 additions and 112 deletions

View file

@ -55,6 +55,7 @@
<ItemGroup>
<PackageReference Include="Droplex" Version="1.3.1" />
<PackageReference Include="FSharp.Core" Version="4.7.1" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.1.3" />
<PackageReference Include="squirrel.windows" Version="1.5.2" />
</ItemGroup>

View file

@ -11,7 +11,9 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
using ICSharpCode.SharpZipLib.Zip;
using JetBrains.Annotations;
using Microsoft.IO;
namespace Flow.Launcher.Core.Plugin
{
@ -33,9 +35,11 @@ namespace Flow.Launcher.Core.Plugin
protected abstract string ExecuteCallback(JsonRPCRequestModel rpcRequest);
protected abstract string ExecuteContextMenu(Result selectedResult);
private static readonly RecyclableMemoryStreamManager BufferManager = new();
public List<Result> LoadContextMenus(Result selectedResult)
{
string output = ExecuteContextMenu(selectedResult);
var output = ExecuteContextMenu(selectedResult);
try
{
return DeserializedResult(output);
@ -61,12 +65,23 @@ namespace Flow.Launcher.Core.Plugin
{
if (output == Stream.Null) return null;
var queryResponseModel = await
JsonSerializer.DeserializeAsync<JsonRPCQueryResponseModel>(output, options);
try
{
var queryResponseModel =
await JsonSerializer.DeserializeAsync<JsonRPCQueryResponseModel>(output, options);
await output.DisposeAsync();
return ParseResults(queryResponseModel);
return ParseResults(queryResponseModel);
}
catch (JsonException e)
{
Log.Exception(GetType().FullName, "Unexpected Json Input", e);
}
finally
{
await output.DisposeAsync();
}
return null;
}
private List<Result> DeserializedResult(string output)
@ -81,7 +96,6 @@ namespace Flow.Launcher.Core.Plugin
private List<Result> ParseResults(JsonRPCQueryResponseModel queryResponseModel)
{
var results = new List<Result>();
if (queryResponseModel.Result == null) return null;
if (!string.IsNullOrEmpty(queryResponseModel.DebugMessage))
@ -89,7 +103,7 @@ namespace Flow.Launcher.Core.Plugin
context.API.ShowMsg(queryResponseModel.DebugMessage);
}
foreach (JsonRPCResult result in queryResponseModel.Result)
foreach (var result in queryResponseModel.Result)
{
result.Action = c =>
{
@ -114,7 +128,8 @@ namespace Flow.Launcher.Core.Plugin
return !result.JsonRPCAction.DontHideAfterAction;
}
var jsonRpcRequestModel = JsonSerializer.Deserialize<JsonRPCRequestModel>(actionResponse, options);
var jsonRpcRequestModel =
JsonSerializer.Deserialize<JsonRPCRequestModel>(actionResponse, options);
if (jsonRpcRequestModel?.Method?.StartsWith("Flow.Launcher.") ?? false)
{
@ -125,9 +140,12 @@ namespace Flow.Launcher.Core.Plugin
return !result.JsonRPCAction.DontHideAfterAction;
};
results.Add(result);
}
var results = new List<Result>();
results.AddRange(queryResponseModel.Result);
return results;
}
@ -217,16 +235,42 @@ namespace Flow.Launcher.Core.Plugin
protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, CancellationToken token = default)
{
Process process = null;
bool disposed = false;
try
{
using var process = Process.Start(startInfo);
process = Process.Start(startInfo);
if (process == null)
{
Log.Error("|JsonRPCPlugin.ExecuteAsync|Can't start new process");
return Stream.Null;
}
var result = process.StandardOutput.BaseStream;
await using var source = process.StandardOutput.BaseStream;
var buffer = BufferManager.GetStream();
token.Register(() =>
{
// ReSharper disable once AccessToModifiedClosure
// Manually Check whether disposed
if (!disposed && !process.HasExited)
process.Kill();
});
try
{
// token expire won't instantly trigger the exception,
// manually kill process at before
await source.CopyToAsync(buffer, token);
}
catch (OperationCanceledException)
{
await buffer.DisposeAsync();
return Stream.Null;
}
buffer.Seek(0, SeekOrigin.Begin);
token.ThrowIfCancellationRequested();
@ -245,7 +289,7 @@ namespace Flow.Launcher.Core.Plugin
return Stream.Null;
}
return result;
return buffer;
}
catch (Exception e)
{
@ -254,15 +298,24 @@ namespace Flow.Launcher.Core.Plugin
e);
return Stream.Null;
}
finally
{
process?.Dispose();
disposed = true;
}
}
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
{
var output = await ExecuteQueryAsync(query, token);
try
{
var output = await ExecuteQueryAsync(query, token);
return await DeserializedResultAsync(output);
}
catch (OperationCanceledException)
{
return null;
}
catch (Exception e)
{
Log.Exception($"|JsonRPCPlugin.Query|Exception when query <{query}>", e);

View file

@ -75,7 +75,7 @@ namespace Flow.Launcher
Http.API = API;
Http.Proxy = _settings.Proxy;
await PluginManager.InitializePlugins(API);
var window = new MainWindow(_settings, _mainVM);
@ -99,6 +99,8 @@ namespace Flow.Launcher
AutoStartup();
AutoUpdates();
API.SaveAppAllSettings();
_mainVM.MainWindowVisibility = _settings.HideOnStartup ? Visibility.Hidden : Visibility.Visible;
Log.Info("|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- ");
});

View file

@ -31,12 +31,15 @@
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorovať klávesové skratky v režime na celú obrazovku</system:String>
<system:String x:Key="pythonDirectory">Priečinok s Pythonom</system:String>
<system:String x:Key="autoUpdates">Automatická aktualizácia</system:String>
<system:String x:Key="autoHideScrollBar">Automaticky skryť posuvník</system:String>
<system:String x:Key="autoHideScrollBarToolTip">Automaticky skrývať posuvník v okne nastavení a zobraziť ho, keď naň prejdete myšou</system:String>
<system:String x:Key="selectPythonDirectory">Vybrať</system:String>
<system:String x:Key="hideOnStartup">Schovať Flow Launcher po spustení</system:String>
<system:String x:Key="hideNotifyIcon">Schovať ikonu z oblasti oznámení</system:String>
<system:String x:Key="querySearchPrecision">Presnosť vyhľadávania</system:String>
<system:String x:Key="ShouldUsePinyin">Použiť Pinyin</system:String>
<system:String x:Key="ShouldUsePinyinToolTip">Umožňuje vyhľadávanie pomocou Pinyin. Pinyin je štandardný systém romanizovaného pravopisu pre transliteráciu čínštiny</system:String>
<system:String x:Key="shadowEffectNotAllowed">Efekt tieňa nie je povolený, kým má aktuálny motív povolený efekt rozostrenia</system:String>
<!--Setting Plugin-->
<system:String x:Key="plugin">Plugin</system:String>
@ -48,6 +51,7 @@
<system:String x:Key="newActionKeyword">Nová akcia skratky:</system:String>
<system:String x:Key="currentPriority">Aktuálna priorita:</system:String>
<system:String x:Key="newPriority">Nová priorita:</system:String>
<system:String x:Key="priority">Priorita:</system:String>
<system:String x:Key="pluginDirectory">Priečinok s pluginmi</system:String>
<system:String x:Key="author">Autor</system:String>
<system:String x:Key="plugin_init_time">Príprava:</system:String>
@ -70,6 +74,7 @@
<system:String x:Key="openResultModifiers">Modifikáčné klávesy na otvorenie výsledkov</system:String>
<system:String x:Key="showOpenResultHotkey">Zobraziť klávesovú skratku</system:String>
<system:String x:Key="customQueryHotkey">Vlastná klávesová skratka na vyhľadávanie</system:String>
<system:String x:Key="customQuery">Dopyt</system:String>
<system:String x:Key="delete">Odstrániť</system:String>
<system:String x:Key="edit">Upraviť</system:String>
<system:String x:Key="add">Pridať</system:String>

View file

@ -1,4 +1,4 @@
<Window x:Class="Flow.Launcher.MainWindow"
<Window x:Class="Flow.Launcher.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
@ -93,7 +93,7 @@
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
<svgc:SvgControl Source="{Binding Image}" HorizontalAlignment="Right" Width="48" Height="48"
<svgc:SvgControl Source="{Binding Image}" HorizontalAlignment="Right" Width="42" Height="42"
Background="Transparent"/>
</Grid>
<Line x:Name="ProgressBar" HorizontalAlignment="Right"

View file

@ -77,54 +77,53 @@ namespace Flow.Launcher
switch (e.PropertyName)
{
case nameof(MainViewModel.MainWindowVisibility):
{
if (_viewModel.MainWindowVisibility == Visibility.Visible)
{
Activate();
QueryTextBox.Focus();
UpdatePosition();
_settings.ActivateTimes++;
if (!_viewModel.LastQuerySelected)
if (_viewModel.MainWindowVisibility == Visibility.Visible)
{
QueryTextBox.SelectAll();
_viewModel.LastQuerySelected = true;
Activate();
QueryTextBox.Focus();
UpdatePosition();
_settings.ActivateTimes++;
if (!_viewModel.LastQuerySelected)
{
QueryTextBox.SelectAll();
_viewModel.LastQuerySelected = true;
}
if (_viewModel.ProgressBarVisibility == Visibility.Visible && isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
}
if (_viewModel.ProgressBarVisibility == Visibility.Visible && isProgressBarStoryboardPaused)
else if (!isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
}
if (!isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
break;
}
case nameof(MainViewModel.ProgressBarVisibility):
{
Dispatcher.Invoke(async () =>
{
if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
{
await Task.Delay(50);
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
else if (_viewModel.MainWindowVisibility == Visibility.Visible &&
isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
}, System.Windows.Threading.DispatcherPriority.Render);
break;
}
break;
}
case nameof(MainViewModel.ProgressBarVisibility):
{
Dispatcher.Invoke(async () =>
{
if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
{
await Task.Delay(50);
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
else if (_viewModel.MainWindowVisibility == Visibility.Visible &&
isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
}, System.Windows.Threading.DispatcherPriority.Render);
break;
}
case nameof(MainViewModel.QueryTextCursorMovedToEnd):
if (_viewModel.QueryTextCursorMovedToEnd)
{
@ -230,10 +229,10 @@ namespace Flow.Launcher
{
if (sender != null && e.OriginalSource != null)
{
var r = (ResultListBox) sender;
var d = (DependencyObject) e.OriginalSource;
var r = (ResultListBox)sender;
var d = (DependencyObject)e.OriginalSource;
var item = ItemsControl.ContainerFromElement(r, d) as ListBoxItem;
var result = (ResultViewModel) item?.DataContext;
var result = (ResultViewModel)item?.DataContext;
if (result != null)
{
if (e.ChangedButton == MouseButton.Left)

View file

@ -38,7 +38,7 @@
<TabControl Height="auto" SelectedIndex="0">
<TabItem Header="{DynamicResource general}">
<ScrollViewer ui:ScrollViewerHelper.AutoHideScrollBars="{Binding AutoHideScrollBar, Mode=OneWay}" Margin="60,0,0,0">
<StackPanel Orientation="Vertical" Margin="0,30,0,0">
<StackPanel Orientation="Vertical" Margin="0,30,0,30">
<ui:ToggleSwitch Margin="10" IsOn="{Binding PortableMode}">
<TextBlock Text="{DynamicResource portableMode}" />
</ui:ToggleSwitch>

View file

@ -10,6 +10,10 @@
<system:String x:Key="plugin_explorer_deletefilefoldersuccess">Deletion successful</system:String>
<system:String x:Key="plugin_explorer_deletefilefoldersuccess_detail">Successfully deleted the {0}</system:String>
<system:String x:Key="plugin_explorer_globalActionKeywordInvalid">Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword</system:String>
<system:String x:Key="plugin_explorer_windowsSearchServiceNotRunning">The required service for Windows Index Search does not appear to be running</system:String>
<system:String x:Key="plugin_explorer_windowsSearchServiceFix">To fix this, start the Windows Search service. Select here to remove this warning</system:String>
<system:String x:Key="plugin_explorer_alternative">The warning message has been switched off. As an alternative for searching files and folders, would you like to install Everything plugin?{0}{0}Select 'Yes' to install Everything plugin, or 'No' to return</system:String>
<system:String x:Key="plugin_explorer_alternative_title">Explorer Alternative</system:String>
<!--Controls-->
<system:String x:Key="plugin_explorer_delete">Delete</system:String>

View file

@ -0,0 +1,66 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!--Dialogues-->
<system:String x:Key="plugin_explorer_make_selection_warning">Najprv vyberte položku</system:String>
<system:String x:Key="plugin_explorer_select_folder_link_warning">Vyberte odkaz na priečinok</system:String>
<system:String x:Key="plugin_explorer_delete_folder_link">Naozaj chcete odstrániť {0}?</system:String>
<system:String x:Key="plugin_explorer_deletefilefolderconfirm">Naozaj chcete natrvalo odstrániť túto položku {0}?</system:String>
<system:String x:Key="plugin_explorer_deletefilefoldersuccess">Odstránenie bolo úspešné</system:String>
<system:String x:Key="plugin_explorer_deletefilefoldersuccess_detail">Úspešne odstránené {0}</system:String>
<system:String x:Key="plugin_explorer_globalActionKeywordInvalid">Priradenie globálnej skratky akcie by mohlo počas vyhľadávania poskytnúť príliš veľa výsledkov. Vyberte si konkrétne kľúčové slovo akcie</system:String>
<system:String x:Key="plugin_explorer_windowsSearchServiceNotRunning">Zdá sa, že požadovaná služba Windows Index Search nie je spustená</system:String>
<system:String x:Key="plugin_explorer_windowsSearchServiceFix">Ak to chcete opraviť, spustite službu Windows Search. Ak chcete odstrániť toto upozornenie, kliknite sem</system:String>
<system:String x:Key="plugin_explorer_alternative">Upozornenie bolo vypnuté. Chceli by ste ako alternatívu na vyhľadávanie súborov a priečinkov nainštalovať plugin Everything?{0}{0}Ak chcete nainštalovať plugin Everything, zvoľte 'Áno', pre návrat zvoľte 'Nie'</system:String>
<system:String x:Key="plugin_explorer_alternative_title">Alternatíva pre Explorer</system:String>
<!--Controls-->
<system:String x:Key="plugin_explorer_delete">Odstrániť</system:String>
<system:String x:Key="plugin_explorer_edit">Upraviť</system:String>
<system:String x:Key="plugin_explorer_add">Pridať</system:String>
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Upraviť skratku akcie</system:String>
<system:String x:Key="plugin_explorer_quickaccesslinks_header">Odkazy Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Vylúčené umiestnenia indexovania</system:String>
<system:String x:Key="plugin_explorer_manageindexoptions">Možnosti indexovania</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_search">Vyhľadávanie:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_pathsearch">Vyhľadávanie umiestnenia:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Vyhľadávanie obsahu súborov:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Vyhľadávanie v indexe:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Aktuálna skratka:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Hotovo</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Povolené</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled_tooltip">Ak je vypnuté, Flow túto možnosť vyhľadávania nevykoná a následne sa vráti späť na "*", aby sa uvoľnila skratka akcie.</system:String>
<!--Plugin Infos-->
<system:String x:Key="plugin_explorer_plugin_name">Explorer</system:String>
<system:String x:Key="plugin_explorer_plugin_description">Vyhľadáva a spravuje súbory a priečinky. Explorer používa indexovanie vyhľadávania vo Windowse</system:String>
<!--Context menu items-->
<system:String x:Key="plugin_explorer_copypath">Kopírovať cestu</system:String>
<system:String x:Key="plugin_explorer_copyfilefolder">Kopírovať</system:String>
<system:String x:Key="plugin_explorer_deletefilefolder">Odstrániť</system:String>
<system:String x:Key="plugin_explorer_path">Umiestnenie:</system:String>
<system:String x:Key="plugin_explorer_deletefilefolder_subtitle">Odstrániť vybrané</system:String>
<system:String x:Key="plugin_explorer_runasdifferentuser">Spustiť ako iný používateľ</system:String>
<system:String x:Key="plugin_explorer_runasdifferentuser_subtitle">Spustí vybranú položku ako používateľ s iným kontom</system:String>
<system:String x:Key="plugin_explorer_opencontainingfolder">Otvoriť umiestnenie priečinka</system:String>
<system:String x:Key="plugin_explorer_opencontainingfolder_subtitle">Otvorí umiestnenie, ktoré obsahuje súbor alebo priečinok</system:String>
<system:String x:Key="plugin_explorer_openwitheditor">Otvoriť editorom:</system:String>
<system:String x:Key="plugin_explorer_excludefromindexsearch">Vylúčiť položku a jej podpriečinky z indexu vyhľadávania</system:String>
<system:String x:Key="plugin_explorer_excludedfromindexsearch_msg">Vylúčiť z indexu vyhľadávania</system:String>
<system:String x:Key="plugin_explorer_openindexingoptions">Otvoriť možnosti vyhľadávania vo Windowse</system:String>
<system:String x:Key="plugin_explorer_openindexingoptions_subtitle">Správa indexovaných súborov a priečinkov</system:String>
<system:String x:Key="plugin_explorer_openindexingoptions_errormsg">Nepodarilo sa otvoriť možnosti indexu vyhľadávania</system:String>
<system:String x:Key="plugin_explorer_add_to_quickaccess_title">Pridať do Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_add_to_quickaccess_subtitle">Pridať tento {0} do Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_addfilefoldersuccess">Úspešne pridané</system:String>
<system:String x:Key="plugin_explorer_addfilefoldersuccess_detail">Úspešne pridané do Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_removefilefoldersuccess">Úspešne odstránené</system:String>
<system:String x:Key="plugin_explorer_removefilefoldersuccess_detail">Úspešne odstránené z Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_contextmenu_titletooltip">Pridať do Rýchleho prístupu, aby ho bolo možné otvoriť pomocou skratky akcie pluginu Explorer</system:String>
<system:String x:Key="plugin_explorer_contextmenu_remove_titletooltip">Odstráni z Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_remove_from_quickaccess_title">Odstrániť z Rýchleho prístupu</system:String>
<system:String x:Key="plugin_explorer_remove_from_quickaccess_subtitle">Odstráni {0} z Rýchleho prístupu</system:String>
</ResourceDictionary>

View file

@ -12,14 +12,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
public class SearchManager
{
private readonly PluginInitContext context;
internal static PluginInitContext Context;
private readonly Settings settings;
internal static Settings Settings;
public SearchManager(Settings settings, PluginInitContext context)
{
this.context = context;
this.settings = settings;
Context = context;
Settings = settings;
}
private class PathEqualityComparator : IEqualityComparer<Result>
@ -71,14 +71,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return allowedActionKeyword switch
{
Settings.ActionKeyword.SearchActionKeyword => settings.SearchActionKeywordEnabled &&
keyword == settings.SearchActionKeyword,
Settings.ActionKeyword.PathSearchActionKeyword => settings.PathSearchKeywordEnabled &&
keyword == settings.PathSearchActionKeyword,
Settings.ActionKeyword.SearchActionKeyword => Settings.SearchActionKeywordEnabled &&
keyword == Settings.SearchActionKeyword,
Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled &&
keyword == Settings.PathSearchActionKeyword,
Settings.ActionKeyword.FileContentSearchActionKeyword => keyword ==
settings.FileContentSearchActionKeyword,
Settings.ActionKeyword.IndexSearchActionKeyword => settings.IndexOnlySearchKeywordEnabled &&
keyword == settings.IndexSearchActionKeyword
Settings.FileContentSearchActionKeyword,
Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexOnlySearchKeywordEnabled &&
keyword == Settings.IndexSearchActionKeyword
};
}
@ -88,18 +88,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search
// This allows the user to type the assigned action keyword and only see the list of quick folder links
if (string.IsNullOrEmpty(query.Search))
return QuickAccess.AccessLinkListAll(query, settings.QuickAccessLinks);
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
var results = new HashSet<Result>(PathEqualityComparator.Instance);
var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, settings.QuickAccessLinks);
var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
results.UnionWith(quickaccessLinks);
var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch);
if (isEnvironmentVariable)
return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, context);
return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context);
// Query is a location path with a full environment variable, eg. %appdata%\somefolder\
var isEnvironmentVariablePath = querySearch[1..].Contains("%\\");
@ -136,22 +136,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search
private async Task<List<Result>> WindowsIndexFileContentSearchAsync(Query query, string querySearchString,
CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
var queryConstructor = new QueryConstructor(Settings);
if (string.IsNullOrEmpty(querySearchString))
return new List<Result>();
return await IndexSearch.WindowsIndexSearchAsync(querySearchString,
queryConstructor.CreateQueryHelper().ConnectionString,
return await IndexSearch.WindowsIndexSearchAsync(
querySearchString,
queryConstructor.CreateQueryHelper(),
queryConstructor.QueryForFileContentSearch,
settings.IndexSearchExcludedSubdirectoryPaths,
Settings.IndexSearchExcludedSubdirectoryPaths,
query,
token).ConfigureAwait(false);
}
public bool IsFileContentSearch(string actionKeyword)
{
return actionKeyword == settings.FileContentSearchActionKeyword;
return actionKeyword == Settings.FileContentSearchActionKeyword;
}
private List<Result> DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token)
@ -176,12 +177,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search
private async Task<List<Result>> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString,
CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
var queryConstructor = new QueryConstructor(Settings);
return await IndexSearch.WindowsIndexSearchAsync(querySearchString,
queryConstructor.CreateQueryHelper().ConnectionString,
return await IndexSearch.WindowsIndexSearchAsync(
querySearchString,
queryConstructor.CreateQueryHelper(),
queryConstructor.QueryForAllFilesAndFolders,
settings.IndexSearchExcludedSubdirectoryPaths,
Settings.IndexSearchExcludedSubdirectoryPaths,
query,
token).ConfigureAwait(false);
}
@ -189,12 +191,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search
private async Task<List<Result>> WindowsIndexTopLevelFolderSearchAsync(Query query, string path,
CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
var queryConstructor = new QueryConstructor(Settings);
return await IndexSearch.WindowsIndexSearchAsync(path,
queryConstructor.CreateQueryHelper().ConnectionString,
return await IndexSearch.WindowsIndexSearchAsync(
path,
queryConstructor.CreateQueryHelper(),
queryConstructor.QueryForTopLevelDirectorySearch,
settings.IndexSearchExcludedSubdirectoryPaths,
Settings.IndexSearchExcludedSubdirectoryPaths,
query,
token).ConfigureAwait(false);
}
@ -203,10 +206,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath);
if (!settings.UseWindowsIndexForDirectorySearch)
if (!Settings.UseWindowsIndexForDirectorySearch)
return false;
if (settings.IndexSearchExcludedSubdirectoryPaths
if (Settings.IndexSearchExcludedSubdirectoryPaths
.Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory)
.StartsWith(x.Path, StringComparison.OrdinalIgnoreCase)))
return false;

View file

@ -5,9 +5,11 @@ using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
@ -84,22 +86,36 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
return results;
}
internal async static Task<List<Result>> WindowsIndexSearchAsync(string searchString, string connectionString,
Func<string, string> constructQuery,
List<AccessLink> exclusionList,
Query query,
CancellationToken token)
internal async static Task<List<Result>> WindowsIndexSearchAsync(
string searchString,
CSearchQueryHelper queryHelper,
Func<string, string> constructQuery,
List<AccessLink> exclusionList,
Query query,
CancellationToken token)
{
var regexMatch = Regex.Match(searchString, reservedStringPattern);
if (regexMatch.Success)
return new List<Result>();
try
{
var constructedQuery = constructQuery(searchString);
var constructedQuery = constructQuery(searchString);
return RemoveResultsInExclusionList(
await ExecuteWindowsIndexSearchAsync(constructedQuery, connectionString, query, token).ConfigureAwait(false),
return RemoveResultsInExclusionList(
await ExecuteWindowsIndexSearchAsync(constructedQuery, queryHelper.ConnectionString, query, token).ConfigureAwait(false),
exclusionList,
token);
}
catch (COMException)
{
// Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
if (!SearchManager.Settings.WarnWindowsSearchServiceOff)
return new List<Result>();
return ResultForWindexSearchOff(query.RawQuery);
}
}
private static List<Result> RemoveResultsInExclusionList(List<Result> results, List<AccessLink> exclusionList, CancellationToken token)
@ -137,9 +153,66 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
internal static bool PathIsIndexed(string path)
{
var csm = new CSearchManager();
var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
return indexManager.IncludedInCrawlScope(path) > 0;
try
{
var csm = new CSearchManager();
var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
return indexManager.IncludedInCrawlScope(path) > 0;
}
catch(COMException)
{
// Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
return false;
}
}
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(string.Format("{0} install everything", pluginsManagerPlugin.Metadata.ActionKeywords[0]));
}
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.Visibility = Visibility.Visible;
mainWindow.Focus();
return false;
},
IcoPath = Constants.ExplorerIconImagePath
}
};
}
private static void LogException(string message, Exception e)

View file

@ -1,4 +1,4 @@
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using System;
@ -33,6 +33,8 @@ namespace Flow.Launcher.Plugin.Explorer
public bool IndexOnlySearchKeywordEnabled { get; set; }
public bool WarnWindowsSearchServiceOff { get; set; } = true;
internal enum ActionKeyword
{
SearchActionKeyword,

View file

@ -9,7 +9,7 @@
"Name": "Explorer",
"Description": "Search and manage files and folders. Explorer utilises Windows Index Search",
"Author": "Jeremy Wu",
"Version": "1.8.0",
"Version": "1.8.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",

View file

@ -17,7 +17,8 @@ namespace Flow.Launcher.Plugin.PluginsManager
public List<Result> LoadContextMenus(Result selectedResult)
{
var pluginManifestInfo = selectedResult.ContextData as UserPlugin;
if(selectedResult.ContextData is not UserPlugin pluginManifestInfo)
return new List<Result>();
return new List<Result>
{

View file

@ -269,7 +269,13 @@ namespace Flow.Launcher.Plugin.PluginsManager
}
return false;
}
},
ContextData =
new UserPlugin
{
Website = x.PluginNewUserPlugin.Website,
UrlSourceCode = x.PluginNewUserPlugin.UrlSourceCode
}
});
return Search(results, uninstallSearch);

View file

@ -6,7 +6,7 @@
"Name": "Plugins Manager",
"Description": "Management of installing, uninstalling or updating Flow Launcher plugins",
"Author": "Jeremy Wu",
"Version": "1.8.3",
"Version": "1.8.4",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",

View file

@ -49,8 +49,8 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be
### Installation
| [Windows 7 and up installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) | `WinGet install "Flow Launcher"` |
| -------------------------------------------------------------------------------------------- | -------------------------------- |
| [Windows 7 and up installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) | [Portable](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Portable.zip) | `WinGet install "Flow Launcher"` |
| --------------------------------- | --------------------------------- | --------------------------------- |
Windows may complain about security due to code not being signed, this will be completed at a later stage. If you downloaded from this repo, you are good to continue the set up.

View file

@ -107,6 +107,13 @@ function Publish-Self-Contained ($p) {
dotnet publish -c Release $csproj /p:PublishProfile=$profile
}
function Publish-Portable ($outputLocation, $version) {
& $outputLocation\Flow-Launcher-v$v.exe --silent | Out-Null
mkdir "$env:LocalAppData\FlowLauncher\app-$version\UserData"
Compress-Archive -Path $env:LocalAppData\FlowLauncher -DestinationPath $outputLocation\Flow-Launcher-Portable.zip
}
function Main {
$p = Build-Path
$v = Build-Version
@ -123,6 +130,8 @@ function Main {
$o = "$p\Output\Packages"
Validate-Directory $o
Pack-Squirrel-Installer $p $v $o
Publish-Portable $o $v
}
}

View file

@ -1,4 +1,4 @@
version: '1.8.0.{build}'
version: '1.8.1.{build}'
init:
- ps: |
@ -36,6 +36,8 @@ artifacts:
name: Plugin nupkg
- path: 'Output\Packages\Flow-Launcher-*.exe'
name: Squirrel Installer
- path: Output\Packages\Flow-Launcher-Portable.zip
name: Portable Version
- path: 'Output\Packages\FlowLauncher-*-full.nupkg'
name: Squirrel nupkg
- path: 'Output\Packages\RELEASES'
@ -47,13 +49,13 @@ deploy:
api_key:
secure: n80IeWR3pN81p0w4uXq4mO0TdTXoJSHHFL+yTB9YBJ0Wni2DjZGYwOFdaWzW4hRi
on:
branch: master
APPVEYOR_REPO_TAG: true
- provider: GitHub
release: v$(flowVersion)
auth_token:
secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES
artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES
draft: true
force_update: true
on:
@ -63,7 +65,19 @@ deploy:
release: v$(flowVersion)
auth_token:
secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES
artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES
force_update: true
on:
APPVEYOR_REPO_TAG: true
environment:
winget_token:
secure: HKfVT2FYZITAG0qqMCePYhIem5a/gzvAgYDSlr6RlXfGmeBUOANUtgJ9X6fNroxN
on_success:
- ps: |
if ($env:APPVEYOR_REPO_BRANCH -eq "master" -and $env:APPVEYOR_REPO_TAG -eq "true")
{
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
.\wingetcreate.exe update Flow-Launcher.Flow-Launcher -s true -u https://github.com/Flow-Launcher/Flow.Launcher/releases/download/v$env:flowVersion/Flow-Launcher-v$env:flowVersion.exe -v $env:flowVersion -t $env:winget_token
}