Skip to content

Commit f8b009e

Browse files
authored
Merge pull request #1479 from VictoriousRaptor/SearchProgramsInPATH
[Program Plugin] Search programs in PATH
2 parents 83a14c1 + 2263c94 commit f8b009e

File tree

6 files changed

+129
-112
lines changed

6 files changed

+129
-112
lines changed

Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Type</system:String>
1717
<system:String x:Key="flowlauncher_plugin_program_reindex">Reindex</system:String>
1818
<system:String x:Key="flowlauncher_plugin_program_indexing">Indexing</system:String>
19-
<system:String x:Key="flowlauncher_plugin_program_index_start">Index Start Menu</system:String>
19+
<system:String x:Key="flowlauncher_plugin_program_index_source">Index Sources</system:String>
20+
<system:String x:Key="flowlauncher_plugin_program_index_option">Options</system:String>
21+
<system:String x:Key="flowlauncher_plugin_program_index_start">Start Menu</system:String>
2022
<system:String x:Key="flowlauncher_plugin_program_index_start_tooltip">When enabled, Flow will load programs from the start menu</system:String>
21-
<system:String x:Key="flowlauncher_plugin_program_index_registry">Index Registry</system:String>
23+
<system:String x:Key="flowlauncher_plugin_program_index_registry">Registry</system:String>
2224
<system:String x:Key="flowlauncher_plugin_program_index_registry_tooltip">When enabled, Flow will load programs from the registry</system:String>
25+
<system:String x:Key="flowlauncher_plugin_program_index_PATH">PATH</system:String>
26+
<system:String x:Key="flowlauncher_plugin_program_index_PATH_tooltip">When enabled, Flow will load programs from the PATH environment variable</system:String>
2327
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath">Hide app path</system:String>
2428
<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>
2529
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>

Plugins/Flow.Launcher.Plugin.Program/Main.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public async Task InitAsync(PluginInitContext context)
102102

103103
var b = Task.Run(() =>
104104
{
105-
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
105+
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPPRogram index cost", IndexUwpPrograms);
106106
});
107107

108108
if (cacheEmpty)

Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
using Flow.Launcher.Plugin.Program.Logger;
1212
using Flow.Launcher.Plugin.SharedCommands;
1313
using Flow.Launcher.Plugin.SharedModels;
14-
using Flow.Launcher.Infrastructure.Logger;
15-
using System.Collections;
1614
using System.Diagnostics;
17-
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
1815
using System.Diagnostics.CodeAnalysis;
1916
using System.Text.RegularExpressions;
2017
using System.Threading.Channels;
@@ -279,6 +276,14 @@ private static Win32 LnkProgram(string path)
279276
program.Valid = false;
280277
return program;
281278
}
279+
catch (FileNotFoundException e)
280+
{
281+
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
282+
"|An unexpected error occurred in the calling method LnkProgram", e);
283+
284+
program.Valid = false;
285+
return program;
286+
}
282287
#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.
283288
catch (Exception e)
284289
{
@@ -352,14 +357,14 @@ private static Win32 ExeProgram(string path)
352357
}
353358
}
354359

355-
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes)
360+
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes, bool recursive = true)
356361
{
357362
if (!Directory.Exists(directory))
358363
return Enumerable.Empty<string>();
359364

360365
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
361366
{
362-
IgnoreInaccessible = true, RecurseSubdirectories = true
367+
IgnoreInaccessible = true, RecurseSubdirectories = recursive
363368
}).Where(x => suffixes.Contains(Extension(x)));
364369
}
365370

@@ -395,7 +400,6 @@ private static IEnumerable<Win32> UnregisteredPrograms(List<Settings.ProgramSour
395400

396401
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes)
397402
{
398-
var disabledProgramsList = Main._settings.DisabledProgramSources;
399403

400404
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
401405
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
@@ -414,6 +418,29 @@ private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes)
414418
return programs;
415419
}
416420

421+
private static IEnumerable<Win32> PATHPrograms(string[] suffixes)
422+
{
423+
var pathEnv = Environment.GetEnvironmentVariable("Path");
424+
if (String.IsNullOrEmpty(pathEnv))
425+
{
426+
return Array.Empty<Win32>();
427+
}
428+
429+
var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant());
430+
431+
var toFilter = paths.AsParallel().SelectMany(p => ProgramPaths(p, suffixes, recursive: false));
432+
433+
var programs = ExceptDisabledSource(toFilter.Distinct())
434+
.Select(x => Extension(x) switch
435+
{
436+
ShortcutExtension => LnkProgram(x),
437+
UrlExtension => UrlProgram(x),
438+
ExeExtension => ExeProgram(x),
439+
_ => Win32Program(x)
440+
});
441+
return programs;
442+
}
443+
417444
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes)
418445
{
419446
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
@@ -566,6 +593,12 @@ public static Win32[] All(Settings settings)
566593
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
567594
}
568595

596+
if (settings.EnablePATHSource)
597+
{
598+
var path = PATHPrograms(settings.GetSuffixes());
599+
autoIndexPrograms = autoIndexPrograms.Concat(path);
600+
}
601+
569602
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
570603

571604
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();

Plugins/Flow.Launcher.Plugin.Program/Settings.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using System.Linq;
55
using System.Text.Json.Serialization;
6+
using PropertyChanged;
67
using Windows.Foundation.Metadata;
78

89
namespace Flow.Launcher.Plugin.Program
@@ -13,7 +14,7 @@ public class Settings
1314
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
1415
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
1516

16-
[Obsolete, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
17+
[Obsolete("Should use GetSuffixes() instead."), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
1718
public string[] ProgramSuffixes { get; set; } = null;
1819
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
1920
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
@@ -111,6 +112,8 @@ private void RemoveRedundantSuffixes()
111112
public bool EnableDescription { get; set; } = false;
112113
public bool HideAppsPath { get; set; } = true;
113114
public bool EnableRegistrySource { get; set; } = true;
115+
public bool EnablePATHSource { get; set; } = true;
116+
114117
public string CustomizedExplorer { get; set; } = Explorer;
115118
public string CustomizedArgs { get; set; } = ExplorerArgs;
116119

Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml

Lines changed: 67 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,88 @@
1010
mc:Ignorable="d">
1111
<Grid Margin="0">
1212
<Grid.RowDefinitions>
13-
<RowDefinition Height="170" />
13+
<RowDefinition Height="Auto" />
14+
<RowDefinition Height="Auto" />
1415
<RowDefinition Height="*" />
1516
<RowDefinition Height="60" />
1617
</Grid.RowDefinitions>
18+
<DockPanel
19+
Margin="70,10,0,8"
20+
HorizontalAlignment="Stretch"
21+
LastChildFill="True">
22+
<TextBlock
23+
MinWidth="120"
24+
Margin="0,5,10,0"
25+
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
26+
<WrapPanel
27+
Width="Auto"
28+
Margin="0,0,14,0"
29+
HorizontalAlignment="Right"
30+
DockPanel.Dock="Right">
31+
<CheckBox
32+
Name="StartMenuEnabled"
33+
Margin="12,0,12,0"
34+
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
35+
IsChecked="{Binding EnableStartMenuSource}"
36+
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
37+
<CheckBox
38+
Name="RegistryEnabled"
39+
Margin="12,0,12,0"
40+
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
41+
IsChecked="{Binding EnableRegistrySource}"
42+
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
43+
44+
<CheckBox
45+
Name="PATHEnabled"
46+
Margin="12,0,12,0"
47+
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
48+
IsChecked="{Binding EnablePATHSource}"
49+
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
50+
</WrapPanel>
51+
</DockPanel>
52+
1753
<StackPanel
18-
Grid.Row="0"
54+
Grid.Row="1"
1955
HorizontalAlignment="Stretch"
2056
Orientation="Vertical">
21-
<StackPanel Width="Auto" Orientation="Vertical">
22-
<StackPanel Width="Auto" Orientation="Horizontal">
23-
<CheckBox
24-
Name="StartMenuEnabled"
25-
Width="220"
26-
Margin="70,8,10,8"
27-
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
28-
IsChecked="{Binding EnableStartMenuSource}"
29-
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
30-
<CheckBox
31-
Name="RegistryEnabled"
32-
Margin="70,8,10,8"
33-
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
34-
IsChecked="{Binding EnableRegistrySource}"
35-
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
36-
</StackPanel>
37-
38-
<Separator
39-
Height="1"
40-
BorderBrush="{DynamicResource Color03B}"
41-
BorderThickness="1" />
42-
<StackPanel Width="Auto" Orientation="Horizontal">
57+
<Separator
58+
Height="1"
59+
BorderBrush="{DynamicResource Color03B}"
60+
BorderThickness="1" />
61+
<DockPanel
62+
Margin="70,10,0,8"
63+
HorizontalAlignment="Stretch"
64+
LastChildFill="True">
65+
<TextBlock
66+
MinWidth="120"
67+
Margin="0,5,10,0"
68+
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
69+
<WrapPanel
70+
Width="Auto"
71+
Margin="0,0,14,0"
72+
HorizontalAlignment="Right"
73+
DockPanel.Dock="Right">
4374
<CheckBox
4475
Name="HideLnkEnabled"
45-
Width="220"
46-
Margin="70,8,10,8"
76+
Margin="12,0,12,0"
4777
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
4878
IsChecked="{Binding HideAppsPath}"
4979
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
5080
<CheckBox
5181
Name="DescriptionEnabled"
52-
Margin="70,8,10,8"
82+
Margin="12,0,12,0"
5383
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
5484
IsChecked="{Binding EnableDescription}"
5585
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
56-
</StackPanel>
57-
<Separator
58-
Height="1"
59-
BorderBrush="{DynamicResource Color03B}"
60-
BorderThickness="1" />
61-
</StackPanel>
86+
</WrapPanel>
87+
</DockPanel>
88+
<Separator
89+
Height="1"
90+
BorderBrush="{DynamicResource Color03B}"
91+
BorderThickness="1" />
6292
<StackPanel
6393
Width="Auto"
64-
Margin="10,6,0,0"
94+
Margin="60,6,0,0"
6595
HorizontalAlignment="Left"
6696
Orientation="Horizontal">
6797
<Button
@@ -107,8 +137,8 @@
107137
</StackPanel>
108138
<ListView
109139
x:Name="programSourceView"
110-
Grid.Row="1"
111-
Margin="20,0,20,0"
140+
Grid.Row="2"
141+
Margin="70,0,20,0"
112142
AllowDrop="True"
113143
BorderBrush="DarkGray"
114144
BorderThickness="1"
@@ -147,7 +177,7 @@
147177
</ListView.View>
148178
</ListView>
149179
<DockPanel
150-
Grid.Row="2"
180+
Grid.Row="3"
151181
Grid.RowSpan="1"
152182
Margin="0,0,20,10">
153183
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
@@ -173,66 +203,3 @@
173203
</DockPanel>
174204
</Grid>
175205
</UserControl>
176-
177-
178-
179-
180-
181-
182-
183-
184-
185-
186-
187-
188-
189-
190-
191-
192-
193-
194-
195-
196-
197-
198-
199-
200-
201-
202-
203-
204-
205-
206-
207-
208-
209-
210-
211-
212-
213-
214-
215-
216-
217-
218-
219-
220-
221-
222-
223-
224-
225-
226-
227-
228-
229-
230-
231-
232-
233-
234-
235-
236-
237-
238-

Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using System.IO;
33
using System.Linq;
44
using System.Threading.Tasks;
@@ -66,6 +66,16 @@ public bool EnableStartMenuSource
6666
}
6767
}
6868

69+
public bool EnablePATHSource
70+
{
71+
get => _settings.EnablePATHSource;
72+
set
73+
{
74+
_settings.EnablePATHSource = value;
75+
ReIndexing();
76+
}
77+
}
78+
6979
public string CustomizedExplorerPath
7080
{
7181
get => _settings.CustomizedExplorer;
@@ -360,4 +370,4 @@ private void Row_OnClick(object sender, RoutedEventArgs e)
360370
}
361371
}
362372
}
363-
}
373+
}

0 commit comments

Comments
 (0)