From fa8cd548f6c11d71cf9dbd91a5c6c1495837222b Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 14:18:13 +0600 Subject: [PATCH 01/11] Add `.`, `./lib`, `./plugin` directories to path for Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 52 ++++++++++++++++++--- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 31 +++++++++++- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 536e69b3d..36160b920 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.IO; using System.Text.Json; using System.Threading; @@ -29,10 +30,6 @@ namespace Flow.Launcher.Core.Plugin _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; _startInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory; - - - //Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable - _startInfo.ArgumentList.Add("-B"); } protected override Task RequestAsync(JsonRPCRequestModel request, CancellationToken token = default) @@ -50,10 +47,51 @@ namespace Flow.Launcher.Core.Plugin // TODO: Async Action return Execute(_startInfo); } + public override async Task InitAsync(PluginInitContext context) { - _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); - _startInfo.ArgumentList.Add(""); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + _startInfo.ArgumentList.Add("-c"); + _startInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{context.CurrentPluginMetadata.ExecuteFilePath}', None, '__main__') + """ + ); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + // Because plugins always expect the JSON data to be in the third argument, and specifying -c + // takes up two arguments, we have to move `-B` to the end. + _startInfo.ArgumentList.Add("-B"); + } + // Run .pyz files as is + else + { + // -B flag is needed to tell python not to write .py[co] files. + // Because .pyc contains location infos which will prevent python portable + _startInfo.ArgumentList.Add("-B"); + _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Plugins always expect the JSON data to be in the third argument + // (we're always setting it as _startInfo.ArgumentList[2] = ...). + _startInfo.ArgumentList.Add(""); + } + await base.InitAsync(context); _startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory; } diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 5c36e0eea..224653ba1 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -33,7 +33,36 @@ namespace Flow.Launcher.Core.Plugin public override async Task InitAsync(PluginInitContext context) { - StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + // Run .py files via `-c ` + if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase)) + { + var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; + var libDirectory = Path.Combine(rootDirectory, "lib"); + var pluginDirectory = Path.Combine(rootDirectory, "plugin"); + var filePath = context.CurrentPluginMetadata.ExecuteFilePath; + + // This makes it easier for plugin authors to import their own modules. + // They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually. + // Instead of running the .py file directly, we pass the code we want to run as a CLI argument. + // This code sets sys.path for the plugin author and then runs the .py file via runpy. + StartInfo.ArgumentList.Add("-c"); + StartInfo.ArgumentList.Add( + $""" + import sys + sys.path.append(r'{rootDirectory}') + sys.path.append(r'{libDirectory}') + sys.path.append(r'{pluginDirectory}') + + import runpy + runpy.run_path(r'{filePath}', None, '__main__') + """ + ); + } + // Run .pyz files as is + else + { + StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + } await base.InitAsync(context); } From d5dd7b44a41322ebdd9e4e97a25e62e653775688 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Thu, 5 Dec 2024 17:37:54 +0600 Subject: [PATCH 02/11] Use PYTHONDONTWRITEBYTECODE instead of -B flag when running Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 11 ++++++----- Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 36160b920..7b670742a 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -26,6 +26,9 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRPC); _startInfo.EnvironmentVariables["PYTHONPATH"] = path; + // Prevent Python from writing .py[co] files. + // Because .pyc contains location infos which will prevent python portable. + _startInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; @@ -76,15 +79,13 @@ namespace Flow.Launcher.Core.Plugin // Plugins always expect the JSON data to be in the third argument // (we're always setting it as _startInfo.ArgumentList[2] = ...). _startInfo.ArgumentList.Add(""); - // Because plugins always expect the JSON data to be in the third argument, and specifying -c - // takes up two arguments, we have to move `-B` to the end. - _startInfo.ArgumentList.Add("-B"); } // Run .pyz files as is else { - // -B flag is needed to tell python not to write .py[co] files. - // Because .pyc contains location infos which will prevent python portable + // No need for -B flag because we're using PYTHONDONTWRITEBYTECODE env variable now, + // but the plugins still expect data to be sent as the third argument, so we're keeping + // the flag here, even though it's not necessary anymore. _startInfo.ArgumentList.Add("-B"); _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); // Plugins always expect the JSON data to be in the third argument diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 224653ba1..03ac0e661 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -26,9 +26,7 @@ namespace Flow.Launcher.Core.Plugin var path = Path.Combine(Constant.ProgramDirectory, JsonRpc); StartInfo.EnvironmentVariables["PYTHONPATH"] = path; - - //Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable - StartInfo.ArgumentList.Add("-B"); + StartInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1"; } public override async Task InitAsync(PluginInitContext context) From 198442621a94de8aabf26e56d58dec751080c294 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 21 Jan 2025 14:37:14 +0800 Subject: [PATCH 03/11] Add support for record key --- Flow.Launcher.Plugin/Result.cs | 17 +++++++++++++++ Flow.Launcher/Storage/TopMostRecord.cs | 18 ++++++++++++---- Flow.Launcher/Storage/UserSelectedRecord.cs | 24 ++++++++++++++++----- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index c6ca81cf3..bb005752e 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -185,6 +185,16 @@ namespace Flow.Launcher.Plugin TitleHighlightData = TitleHighlightData, OriginQuery = OriginQuery, PluginDirectory = PluginDirectory, + ContextData = ContextData, + PluginID = PluginID, + TitleToolTip = TitleToolTip, + SubTitleToolTip = SubTitleToolTip, + PreviewPanel = PreviewPanel, + ProgressBar = ProgressBar, + ProgressBarColor = ProgressBarColor, + Preview = Preview, + AddSelectedCount = AddSelectedCount, + RecordKey = RecordKey }; } @@ -252,6 +262,13 @@ namespace Flow.Launcher.Plugin /// public const int MaxScore = int.MaxValue; + /// + /// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records. + /// This can be useful when your plugin will change the Title or SubTitle of the result dynamically. + /// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result. + /// + public string RecordKey { get; set; } = string.Empty; + /// /// Info of the preview section of a /// diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs index cbd0b88fc..05cf01401 100644 --- a/Flow.Launcher/Storage/TopMostRecord.cs +++ b/Flow.Launcher/Storage/TopMostRecord.cs @@ -33,7 +33,8 @@ namespace Flow.Launcher.Storage { PluginID = result.PluginID, Title = result.Title, - SubTitle = result.SubTitle + SubTitle = result.SubTitle, + RecordKey = result.RecordKey }; records.AddOrUpdate(result.OriginQuery.RawQuery, record, (key, oldValue) => record); } @@ -49,12 +50,21 @@ namespace Flow.Launcher.Storage public string Title { get; set; } public string SubTitle { get; set; } public string PluginID { get; set; } + public string RecordKey { get; set; } public bool Equals(Result r) { - return Title == r.Title - && SubTitle == r.SubTitle - && PluginID == r.PluginID; + if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey)) + { + return Title == r.Title + && SubTitle == r.SubTitle + && PluginID == r.PluginID; + } + else + { + return RecordKey == r.RecordKey + && PluginID == r.PluginID; + } } } } diff --git a/Flow.Launcher/Storage/UserSelectedRecord.cs b/Flow.Launcher/Storage/UserSelectedRecord.cs index d6405005d..6da36747d 100644 --- a/Flow.Launcher/Storage/UserSelectedRecord.cs +++ b/Flow.Launcher/Storage/UserSelectedRecord.cs @@ -15,7 +15,6 @@ namespace Flow.Launcher.Storage [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Dictionary records { get; private set; } - public UserSelectedRecord() { recordsWithQuery = new Dictionary(); @@ -45,8 +44,15 @@ namespace Flow.Launcher.Storage private static int GenerateResultHashCode(Result result) { - int hashcode = GenerateStaticHashCode(result.Title); - return GenerateStaticHashCode(result.SubTitle, hashcode); + if (string.IsNullOrEmpty(result.RecordKey)) + { + int hashcode = GenerateStaticHashCode(result.Title); + return GenerateStaticHashCode(result.SubTitle, hashcode); + } + else + { + return GenerateStaticHashCode(result.RecordKey); + } } private static int GenerateQueryAndResultHashCode(Query query, Result result) @@ -58,8 +64,16 @@ namespace Flow.Launcher.Storage int hashcode = GenerateStaticHashCode(query.ActionKeyword); hashcode = GenerateStaticHashCode(query.Search, hashcode); - hashcode = GenerateStaticHashCode(result.Title, hashcode); - hashcode = GenerateStaticHashCode(result.SubTitle, hashcode); + + if (string.IsNullOrEmpty(result.RecordKey)) + { + hashcode = GenerateStaticHashCode(result.Title, hashcode); + hashcode = GenerateStaticHashCode(result.SubTitle, hashcode); + } + else + { + hashcode = GenerateStaticHashCode(result.RecordKey, hashcode); + } return hashcode; } From bb7900c0e0da0f9a3eefbaa953c19e98cb9c06f6 Mon Sep 17 00:00:00 2001 From: Yusyuriv Date: Sun, 2 Feb 2025 15:27:02 +0600 Subject: [PATCH 04/11] Add PyWin32-related directories to path for Python plugins --- Flow.Launcher.Core/Plugin/PythonPlugin.cs | 4 ++++ Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Flow.Launcher.Core/Plugin/PythonPlugin.cs b/Flow.Launcher.Core/Plugin/PythonPlugin.cs index 7b670742a..e40b0330e 100644 --- a/Flow.Launcher.Core/Plugin/PythonPlugin.cs +++ b/Flow.Launcher.Core/Plugin/PythonPlugin.cs @@ -58,6 +58,8 @@ namespace Flow.Launcher.Core.Plugin { var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; var libDirectory = Path.Combine(rootDirectory, "lib"); + var libPyWin32Directory = Path.Combine(libDirectory, "win32"); + var libPyWin32LibDirectory = Path.Combine(libPyWin32Directory, "lib"); var pluginDirectory = Path.Combine(rootDirectory, "plugin"); // This makes it easier for plugin authors to import their own modules. @@ -70,6 +72,8 @@ namespace Flow.Launcher.Core.Plugin import sys sys.path.append(r'{rootDirectory}') sys.path.append(r'{libDirectory}') + sys.path.append(r'{libPyWin32LibDirectory}') + sys.path.append(r'{libPyWin32Directory}') sys.path.append(r'{pluginDirectory}') import runpy diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 03ac0e661..8a9e1ff44 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -36,6 +36,8 @@ namespace Flow.Launcher.Core.Plugin { var rootDirectory = context.CurrentPluginMetadata.PluginDirectory; var libDirectory = Path.Combine(rootDirectory, "lib"); + var libPyWin32Directory = Path.Combine(libDirectory, "win32"); + var libPyWin32LibDirectory = Path.Combine(libPyWin32Directory, "lib"); var pluginDirectory = Path.Combine(rootDirectory, "plugin"); var filePath = context.CurrentPluginMetadata.ExecuteFilePath; @@ -49,6 +51,8 @@ namespace Flow.Launcher.Core.Plugin import sys sys.path.append(r'{rootDirectory}') sys.path.append(r'{libDirectory}') + sys.path.append(r'{libPyWin32LibDirectory}') + sys.path.append(r'{libPyWin32Directory}') sys.path.append(r'{pluginDirectory}') import runpy From f708ad9ffdb823282e522b31608289e68beefcd2 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:18:21 +0100 Subject: [PATCH 05/11] Add Windows Terminal to Shell Plugin --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 27 +++++++++++++++++++ .../Flow.Launcher.Plugin.Shell/Settings.cs | 2 ++ .../ShellSetting.xaml | 4 ++- .../ShellSetting.xaml.cs | 4 +++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 921c6bc21..a192b8900 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -279,6 +279,33 @@ namespace Flow.Launcher.Plugin.Shell break; } + case Shell.TerminalPWSH: + { + info.filename = "wt.exe" + info.ArgumentList.Add("pwsh"); + if (_settings.LeaveShellOpen) + { + info.ArgumentList.Add("-NoExit"); + } + info.ArgumentList.Add("-Command"); + info.ArgumentList.Add(command); + break; + } + case Shell.TerminalCMD: + { + info.filename = "wt.exe" + info.ArgumentList.Add("cmd"); + if (_settings.LeaveShellOpen) + { + info.ArgumentList.Add("/k"); + } + else + { + info.ArgumentList.Add("/c"); + } + info.ArgumentList.Add(command); + break; + } default: throw new NotImplementedException(); } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs index 6f47d5d17..75cc56618 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs @@ -39,5 +39,7 @@ namespace Flow.Launcher.Plugin.Shell Powershell = 1, RunCommand = 2, Pwsh = 3, + TerminalPWSH = 4, + TerminalCMD = 5, } } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 2f02ef723..22f4ff22d 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -43,12 +43,14 @@ Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" /> CMD PowerShell Pwsh + Terminal (Pwsh) + Terminal (CMD) RunCommand diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs index 24365f2aa..e981f8b74 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs @@ -91,6 +91,8 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, + Shell.TerminalPWSH = 3, + Shell.TerminalCMD = 4, _ => ShellComboBox.Items.Count - 1 }; @@ -101,6 +103,8 @@ namespace Flow.Launcher.Plugin.Shell 0 => Shell.Cmd, 1 => Shell.Powershell, 2 => Shell.Pwsh, + 3 => Shell.TerminalPWSH, + 4 => Shell.TerminalCMD, _ => Shell.RunCommand }; LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand; From ff2f0c375cd90ff721739cdc68e406b4ecdae4d3 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:39:29 +0100 Subject: [PATCH 06/11] Fix typos --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 4 ++-- Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index a192b8900..60c8ba1a8 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -281,7 +281,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalPWSH: { - info.filename = "wt.exe" + info.filename = "wt.exe"; info.ArgumentList.Add("pwsh"); if (_settings.LeaveShellOpen) { @@ -293,7 +293,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalCMD: { - info.filename = "wt.exe" + info.filename = "wt.exe"; info.ArgumentList.Add("cmd"); if (_settings.LeaveShellOpen) { diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs index e981f8b74..eaac8731a 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml.cs @@ -91,8 +91,8 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, - Shell.TerminalPWSH = 3, - Shell.TerminalCMD = 4, + Shell.TerminalPWSH => 3, + Shell.TerminalCMD => 4, _ => ShellComboBox.Items.Count - 1 }; From 3596a77b343bd0a0332a7cde43228bb9affcaaa3 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Tue, 4 Feb 2025 23:54:04 +0100 Subject: [PATCH 07/11] Fix the rest of my mistakes --- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 4 ++-- Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 60c8ba1a8..fc8746e41 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -281,7 +281,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalPWSH: { - info.filename = "wt.exe"; + info.FileName = "wt.exe"; info.ArgumentList.Add("pwsh"); if (_settings.LeaveShellOpen) { @@ -293,7 +293,7 @@ namespace Flow.Launcher.Plugin.Shell } case Shell.TerminalCMD: { - info.filename = "wt.exe"; + info.FileName = "wt.exe"; info.ArgumentList.Add("cmd"); if (_settings.LeaveShellOpen) { diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 22f4ff22d..7e35a872f 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -43,7 +43,7 @@ Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" /> CMD From 5bb3d724c026e7cc2bd8b22079cd4e94173f14e1 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Thu, 6 Feb 2025 00:22:41 +0100 Subject: [PATCH 08/11] Use a checkbox instead of separate entries --- .../Languages/en.xaml | 3 +- .../Languages/es-419.xaml | 1 + .../Languages/es.xaml | 1 + Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 77 ++++++++----------- .../Flow.Launcher.Plugin.Shell/Settings.cs | 4 +- .../ShellSetting.xaml | 13 +++- .../ShellSetting.xaml.cs | 16 +++- 7 files changed, 57 insertions(+), 58 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml index 52aaf3c27..645a0e14f 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/en.xaml @@ -7,6 +7,7 @@ Press any key to close this window... Do not close Command Prompt after command execution Always run as administrator + Use Windows Terminal Run as different user Shell Allows to execute system commands from Flow Launcher @@ -15,4 +16,4 @@ Run As Administrator Copy the command Only show number of most used commands: - \ No newline at end of file + diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml index 5ee2c43b4..f3ef0df0a 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml @@ -6,6 +6,7 @@ Press any key to close this window... No cerrar Símbolo del Sistema tras ejecutar el comando Siempre ejecutar como administrador + Ejecutar en la Terminal de Windows Ejecutar como otro usuario Shell Allows to execute system commands from Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml index a3ee35ef8..ee3193b16 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml @@ -6,6 +6,7 @@ Pulsar cualquier tecla para cerrar esta ventana... No cerrar el símbolo del sistema después de la ejecución del comando Ejecutar siempre como administrador + Ejecutar en la Terminal de Windows Ejecutar como usuario diferente Terminal Permite ejecutar comandos del sistema desde Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index fc8746e41..7f1f4bd4d 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -202,28 +202,31 @@ namespace Flow.Launcher.Plugin.Shell { case Shell.Cmd: { - info.FileName = "cmd.exe"; - info.Arguments = $"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command} {(_settings.CloseShellAfterPress ? $"&& echo {context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")} && pause > nul /c" : "")}"; - - //// Use info.Arguments instead of info.ArgumentList to enable users better control over the arguments they are writing. - //// Previous code using ArgumentList, commands needed to be separated correctly: - //// Incorrect: - // info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c"); - // info.ArgumentList.Add(command); //<== info.ArgumentList.Add("mkdir \"c:\\test new\""); - - //// Correct version should be: - //info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c"); - //info.ArgumentList.Add("mkdir"); - //info.ArgumentList.Add(@"c:\test new"); - - //https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0#remarks + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("cmd"); + } + else + { + info.FileName = "cmd.exe"; + } + info.ArgumentList.Add($"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command} {(_settings.CloseShellAfterPress ? $"&& echo {context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")} && pause > nul /c" : "")}"); break; } case Shell.Powershell: { - info.FileName = "powershell.exe"; + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("powershell"); + } + else + { + info.FileName = "powershell.exe"; + } if (_settings.LeaveShellOpen) { info.ArgumentList.Add("-NoExit"); @@ -232,21 +235,28 @@ namespace Flow.Launcher.Plugin.Shell else { info.ArgumentList.Add("-Command"); - info.ArgumentList.Add($"{command}; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'; [System.Console]::ReadKey(); exit" : "")}"); + info.ArgumentList.Add($"{command}\\; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'\\; [System.Console]::ReadKey()\\; exit" : "")}"); } break; } case Shell.Pwsh: { - info.FileName = "pwsh.exe"; + if (_settings.UseWindowsTerminal) + { + info.FileName = "wt.exe"; + info.ArgumentList.Add("pwsh"); + } + else + { + info.FileName = "pwsh.exe"; + } if (_settings.LeaveShellOpen) { info.ArgumentList.Add("-NoExit"); } info.ArgumentList.Add("-Command"); - info.ArgumentList.Add($"{command}; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'; [System.Console]::ReadKey(); exit" : "")}"); - + info.ArgumentList.Add($"{command}\\; {(_settings.CloseShellAfterPress ? $"Write-Host '{context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'\\; [System.Console]::ReadKey()\\; exit" : "")}"); break; } @@ -279,33 +289,6 @@ namespace Flow.Launcher.Plugin.Shell break; } - case Shell.TerminalPWSH: - { - info.FileName = "wt.exe"; - info.ArgumentList.Add("pwsh"); - if (_settings.LeaveShellOpen) - { - info.ArgumentList.Add("-NoExit"); - } - info.ArgumentList.Add("-Command"); - info.ArgumentList.Add(command); - break; - } - case Shell.TerminalCMD: - { - info.FileName = "wt.exe"; - info.ArgumentList.Add("cmd"); - if (_settings.LeaveShellOpen) - { - info.ArgumentList.Add("/k"); - } - else - { - info.ArgumentList.Add("/c"); - } - info.ArgumentList.Add(command); - break; - } default: throw new NotImplementedException(); } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs index 75cc56618..9ce2293a2 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Settings.cs @@ -14,6 +14,8 @@ namespace Flow.Launcher.Plugin.Shell public bool RunAsAdministrator { get; set; } = true; + public bool UseWindowsTerminal { get; set; } = false; + public bool ShowOnlyMostUsedCMDs { get; set; } public int ShowOnlyMostUsedCMDsNumber { get; set; } @@ -39,7 +41,5 @@ namespace Flow.Launcher.Plugin.Shell Powershell = 1, RunCommand = 2, Pwsh = 3, - TerminalPWSH = 4, - TerminalCMD = 5, } } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml index 7e35a872f..8a3b7f115 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/ShellSetting.xaml @@ -16,6 +16,7 @@ + + CMD PowerShell Pwsh - Terminal (Pwsh) - Terminal (CMD) RunCommand - + + { + _settings.UseWindowsTerminal = true; + }; + + UseWindowsTerminal.Unchecked += (o, e) => + { + _settings.UseWindowsTerminal = false; + }; + ReplaceWinR.Checked += (o, e) => { _settings.ReplaceWinR = true; @@ -91,8 +103,6 @@ namespace Flow.Launcher.Plugin.Shell Shell.Cmd => 0, Shell.Powershell => 1, Shell.Pwsh => 2, - Shell.TerminalPWSH => 3, - Shell.TerminalCMD => 4, _ => ShellComboBox.Items.Count - 1 }; @@ -103,8 +113,6 @@ namespace Flow.Launcher.Plugin.Shell 0 => Shell.Cmd, 1 => Shell.Powershell, 2 => Shell.Pwsh, - 3 => Shell.TerminalPWSH, - 4 => Shell.TerminalCMD, _ => Shell.RunCommand }; LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand; From 6c081e12a4c97e432dc69d5a262f97d3010f7a14 Mon Sep 17 00:00:00 2001 From: Azakidev Date: Sat, 8 Feb 2025 19:26:36 +0100 Subject: [PATCH 09/11] Revert the translation files --- Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml | 1 - Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml | 1 - 2 files changed, 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml index f3ef0df0a..5ee2c43b4 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es-419.xaml @@ -6,7 +6,6 @@ Press any key to close this window... No cerrar Símbolo del Sistema tras ejecutar el comando Siempre ejecutar como administrador - Ejecutar en la Terminal de Windows Ejecutar como otro usuario Shell Allows to execute system commands from Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml index ee3193b16..a3ee35ef8 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/es.xaml @@ -6,7 +6,6 @@ Pulsar cualquier tecla para cerrar esta ventana... No cerrar el símbolo del sistema después de la ejecución del comando Ejecutar siempre como administrador - Ejecutar en la Terminal de Windows Ejecutar como usuario diferente Terminal Permite ejecutar comandos del sistema desde Flow Launcher From 980795ba00fa66fe477e92f92e58509a30e39c2e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 12 Feb 2025 10:21:14 +0800 Subject: [PATCH 10/11] Improve explorer path parse when path ends with backslash --- .../FileExplorerHelper.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs index d908b0fde..b97c096c3 100644 --- a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs +++ b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs @@ -15,7 +15,20 @@ namespace Flow.Launcher.Infrastructure { var explorerWindow = GetActiveExplorer(); string locationUrl = explorerWindow?.LocationURL; - return !string.IsNullOrEmpty(locationUrl) ? new Uri(locationUrl).LocalPath + "\\" : null; + return !string.IsNullOrEmpty(locationUrl) ? GetDirectoryPath(new Uri(locationUrl).LocalPath) : null; + } + + /// + /// Get directory path from a file path + /// + private static string GetDirectoryPath(string path) + { + if (!path.EndsWith("\\")) + { + return path + "\\"; + } + + return path; } /// From 9284c559f68cc8418af9cea727c8954b01153e6c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 18 Feb 2025 11:41:26 +0800 Subject: [PATCH 11/11] Use api function to hide window --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 8 ++++---- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 671489846..c1ed904b3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -534,7 +534,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(plugin); return ShouldHideWindow; @@ -572,7 +572,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(plugin); return ShouldHideWindow; @@ -626,7 +626,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return ShouldHideWindow; } - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); _ = InstallOrUpdateAsync(x); // No need to wait return ShouldHideWindow; }, @@ -703,7 +703,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) { - Application.Current.MainWindow.Hide(); + Context.API.HideMainWindow(); Uninstall(x.Metadata); if (Settings.AutoRestartAfterChanging) { diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 5bfc68ea6..edf9c82e4 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -333,7 +333,7 @@ namespace Flow.Launcher.Plugin.Sys Action = c => { // Hide the window first then show msg after done because sometimes the reload could take a while, so not to make user think it's frozen. - Application.Current.MainWindow.Hide(); + context.API.HideMainWindow(); _ = context.API.ReloadAllPluginData().ContinueWith(_ => context.API.ShowMsg( @@ -352,7 +352,7 @@ namespace Flow.Launcher.Plugin.Sys IcoPath = "Images\\checkupdate.png", Action = c => { - Application.Current.MainWindow.Hide(); + context.API.HideMainWindow(); context.API.CheckForNewUpdate(); return true; }