Merge pull request #1479 from VictoriousRaptor/SearchProgramsInPATH

[Program Plugin] Search programs in PATH
This commit is contained in:
Jeremy Wu 2022-11-14 13:31:45 +11:00 committed by GitHub
commit f8b009ed75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 112 deletions

View file

@ -16,10 +16,14 @@
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Type</system:String>
<system:String x:Key="flowlauncher_plugin_program_reindex">Reindex</system:String>
<system:String x:Key="flowlauncher_plugin_program_indexing">Indexing</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start">Index Start Menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_source">Index Sources</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_option">Options</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start">Start Menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start_tooltip">When enabled, Flow will load programs from the start menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry">Index Registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry">Registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry_tooltip">When enabled, Flow will load programs from the registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_PATH">PATH</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_PATH_tooltip">When enabled, Flow will load programs from the PATH environment variable</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath">Hide app path</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath_tooltip">For executable files such as UWP or lnk, hide the file path from being visible</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>

View file

@ -102,7 +102,7 @@ namespace Flow.Launcher.Plugin.Program
var b = Task.Run(() =>
{
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPPRogram index cost", IndexUwpPrograms);
});
if (cacheEmpty)

View file

@ -11,10 +11,7 @@ using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.Program.Logger;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Infrastructure.Logger;
using System.Collections;
using System.Diagnostics;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using System.Threading.Channels;
@ -279,6 +276,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
program.Valid = false;
return program;
}
catch (FileNotFoundException e)
{
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
"|An unexpected error occurred in the calling method LnkProgram", e);
program.Valid = false;
return program;
}
#if !DEBUG //Only do a catch all in production. This is so make developer aware of any unhandled exception and add the exception handling in.
catch (Exception e)
{
@ -352,14 +357,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
}
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes)
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes, bool recursive = true)
{
if (!Directory.Exists(directory))
return Enumerable.Empty<string>();
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
{
IgnoreInaccessible = true, RecurseSubdirectories = true
IgnoreInaccessible = true, RecurseSubdirectories = recursive
}).Where(x => suffixes.Contains(Extension(x)));
}
@ -395,7 +400,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes)
{
var disabledProgramsList = Main._settings.DisabledProgramSources;
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
@ -414,6 +418,29 @@ namespace Flow.Launcher.Plugin.Program.Programs
return programs;
}
private static IEnumerable<Win32> PATHPrograms(string[] suffixes)
{
var pathEnv = Environment.GetEnvironmentVariable("Path");
if (String.IsNullOrEmpty(pathEnv))
{
return Array.Empty<Win32>();
}
var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant());
var toFilter = paths.AsParallel().SelectMany(p => ProgramPaths(p, suffixes, recursive: false));
var programs = ExceptDisabledSource(toFilter.Distinct())
.Select(x => Extension(x) switch
{
ShortcutExtension => LnkProgram(x),
UrlExtension => UrlProgram(x),
ExeExtension => ExeProgram(x),
_ => Win32Program(x)
});
return programs;
}
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes)
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
@ -566,6 +593,12 @@ namespace Flow.Launcher.Plugin.Program.Programs
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
}
if (settings.EnablePATHSource)
{
var path = PATHPrograms(settings.GetSuffixes());
autoIndexPrograms = autoIndexPrograms.Concat(path);
}
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using PropertyChanged;
using Windows.Foundation.Metadata;
namespace Flow.Launcher.Plugin.Program
@ -13,7 +14,7 @@ namespace Flow.Launcher.Plugin.Program
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
[Obsolete, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[Obsolete("Should use GetSuffixes() instead."), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string[] ProgramSuffixes { get; set; } = null;
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
@ -111,6 +112,8 @@ namespace Flow.Launcher.Plugin.Program
public bool EnableDescription { get; set; } = false;
public bool HideAppsPath { get; set; } = true;
public bool EnableRegistrySource { get; set; } = true;
public bool EnablePATHSource { get; set; } = true;
public string CustomizedExplorer { get; set; } = Explorer;
public string CustomizedArgs { get; set; } = ExplorerArgs;

View file

@ -10,58 +10,88 @@
mc:Ignorable="d">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="170" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<DockPanel
Margin="70,10,0,8"
HorizontalAlignment="Stretch"
LastChildFill="True">
<TextBlock
MinWidth="120"
Margin="0,5,10,0"
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
<WrapPanel
Width="Auto"
Margin="0,0,14,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right">
<CheckBox
Name="StartMenuEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
IsChecked="{Binding EnableStartMenuSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
<CheckBox
Name="RegistryEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
IsChecked="{Binding EnableRegistrySource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
<CheckBox
Name="PATHEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
IsChecked="{Binding EnablePATHSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
</WrapPanel>
</DockPanel>
<StackPanel
Grid.Row="0"
Grid.Row="1"
HorizontalAlignment="Stretch"
Orientation="Vertical">
<StackPanel Width="Auto" Orientation="Vertical">
<StackPanel Width="Auto" Orientation="Horizontal">
<CheckBox
Name="StartMenuEnabled"
Width="220"
Margin="70,8,10,8"
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
IsChecked="{Binding EnableStartMenuSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
<CheckBox
Name="RegistryEnabled"
Margin="70,8,10,8"
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
IsChecked="{Binding EnableRegistrySource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
</StackPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<StackPanel Width="Auto" Orientation="Horizontal">
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<DockPanel
Margin="70,10,0,8"
HorizontalAlignment="Stretch"
LastChildFill="True">
<TextBlock
MinWidth="120"
Margin="0,5,10,0"
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
<WrapPanel
Width="Auto"
Margin="0,0,14,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right">
<CheckBox
Name="HideLnkEnabled"
Width="220"
Margin="70,8,10,8"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
IsChecked="{Binding HideAppsPath}"
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
<CheckBox
Name="DescriptionEnabled"
Margin="70,8,10,8"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
IsChecked="{Binding EnableDescription}"
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
</StackPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
</StackPanel>
</WrapPanel>
</DockPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<StackPanel
Width="Auto"
Margin="10,6,0,0"
Margin="60,6,0,0"
HorizontalAlignment="Left"
Orientation="Horizontal">
<Button
@ -107,8 +137,8 @@
</StackPanel>
<ListView
x:Name="programSourceView"
Grid.Row="1"
Margin="20,0,20,0"
Grid.Row="2"
Margin="70,0,20,0"
AllowDrop="True"
BorderBrush="DarkGray"
BorderThickness="1"
@ -147,7 +177,7 @@
</ListView.View>
</ListView>
<DockPanel
Grid.Row="2"
Grid.Row="3"
Grid.RowSpan="1"
Margin="0,0,20,10">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
@ -173,66 +203,3 @@
</DockPanel>
</Grid>
</UserControl>

View file

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -66,6 +66,16 @@ namespace Flow.Launcher.Plugin.Program.Views
}
}
public bool EnablePATHSource
{
get => _settings.EnablePATHSource;
set
{
_settings.EnablePATHSource = value;
ReIndexing();
}
}
public string CustomizedExplorerPath
{
get => _settings.CustomizedExplorer;
@ -360,4 +370,4 @@ namespace Flow.Launcher.Plugin.Program.Views
}
}
}
}
}