mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #1498 from Flow-Launcher/add_nodejs_env
Add Node.js environment setup
This commit is contained in:
commit
944e0f140f
46 changed files with 566 additions and 212 deletions
|
|
@ -0,0 +1,234 @@
|
|||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
public abstract class AbstractPluginEnvironment
|
||||
{
|
||||
internal abstract string Language { get; }
|
||||
|
||||
internal abstract string EnvName { get; }
|
||||
|
||||
internal abstract string EnvPath { get; }
|
||||
|
||||
internal abstract string InstallPath { get; }
|
||||
|
||||
internal abstract string ExecutablePath { get; }
|
||||
|
||||
internal virtual string FileDialogFilter => string.Empty;
|
||||
|
||||
internal abstract string PluginsSettingsFilePath { get; set; }
|
||||
|
||||
internal List<PluginMetadata> PluginMetadataList;
|
||||
|
||||
internal PluginsSettings PluginSettings;
|
||||
|
||||
internal AbstractPluginEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings)
|
||||
{
|
||||
PluginMetadataList = pluginMetadataList;
|
||||
PluginSettings = pluginSettings;
|
||||
}
|
||||
|
||||
internal IEnumerable<PluginPair> Setup()
|
||||
{
|
||||
if (!PluginMetadataList.Any(o => o.Language.Equals(Language, StringComparison.OrdinalIgnoreCase)))
|
||||
return new List<PluginPair>();
|
||||
|
||||
// TODO: Remove. This is backwards compatibility for 1.10.0 release- changed PythonEmbeded to Environments/Python
|
||||
if (Language.Equals(AllowedLanguage.Python, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
FilesFolders.RemoveFolderIfExists(Path.Combine(DataLocation.DataDirectory(), "PythonEmbeddable"));
|
||||
|
||||
if (!string.IsNullOrEmpty(PluginSettings.PythonDirectory) && PluginSettings.PythonDirectory.StartsWith(Path.Combine(DataLocation.DataDirectory(), "PythonEmbeddable")))
|
||||
{
|
||||
InstallEnvironment();
|
||||
PluginSettings.PythonDirectory = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath))
|
||||
{
|
||||
// Ensure latest only if user is using Flow's environment setup.
|
||||
if (PluginsSettingsFilePath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
|
||||
EnsureLatestInstalled(ExecutablePath, PluginsSettingsFilePath, EnvPath);
|
||||
|
||||
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
|
||||
}
|
||||
|
||||
if (MessageBox.Show($"Flow detected you have installed {Language} plugins, which " +
|
||||
$"will require {EnvName} to run. Would you like to download {EnvName}? " +
|
||||
Environment.NewLine + Environment.NewLine +
|
||||
"Click no if it's already installed, " +
|
||||
$"and you will be prompted to select the folder that contains the {EnvName} executable",
|
||||
string.Empty, MessageBoxButtons.YesNo) == DialogResult.No)
|
||||
{
|
||||
var msg = $"Please select the {EnvName} executable";
|
||||
var selectedFile = string.Empty;
|
||||
|
||||
selectedFile = GetFileFromDialog(msg, FileDialogFilter);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
PluginsSettingsFilePath = selectedFile;
|
||||
|
||||
// Nothing selected because user pressed cancel from the file dialog window
|
||||
if (string.IsNullOrEmpty(selectedFile))
|
||||
InstallEnvironment();
|
||||
}
|
||||
else
|
||||
{
|
||||
InstallEnvironment();
|
||||
}
|
||||
|
||||
if (FilesFolders.FileExists(PluginsSettingsFilePath))
|
||||
{
|
||||
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(
|
||||
$"Unable to set {Language} executable path, please try from Flow's settings (scroll down to the bottom).");
|
||||
Log.Error("PluginsLoader",
|
||||
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
|
||||
$"{Language}Environment");
|
||||
|
||||
return new List<PluginPair>();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract void InstallEnvironment();
|
||||
|
||||
private void EnsureLatestInstalled(string expectedPath, string currentPath, string installedDirPath)
|
||||
{
|
||||
if (expectedPath == currentPath)
|
||||
return;
|
||||
|
||||
FilesFolders.RemoveFolderIfExists(installedDirPath);
|
||||
|
||||
InstallEnvironment();
|
||||
|
||||
}
|
||||
|
||||
internal abstract PluginPair CreatePluginPair(string filePath, PluginMetadata metadata);
|
||||
|
||||
private IEnumerable<PluginPair> SetPathForPluginPairs(string filePath, string languageToSet)
|
||||
{
|
||||
var pluginPairs = new List<PluginPair>();
|
||||
|
||||
foreach (var metadata in PluginMetadataList)
|
||||
{
|
||||
if (metadata.Language.Equals(languageToSet, StringComparison.OrdinalIgnoreCase))
|
||||
pluginPairs.Add(CreatePluginPair(filePath, metadata));
|
||||
}
|
||||
|
||||
return pluginPairs;
|
||||
}
|
||||
|
||||
private string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
Multiselect = false,
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
Title = title,
|
||||
Filter = filter
|
||||
};
|
||||
|
||||
var result = dlg.ShowDialog();
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
return dlg.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// After app updated while in portable mode or switched between portable/roaming mode,
|
||||
/// need to update each plugin's executable path so user will not be prompted again to reinstall the environments.
|
||||
/// </summary>
|
||||
/// <param name="settings"></param>
|
||||
public static void PreStartPluginExecutablePathUpdate(Settings settings)
|
||||
{
|
||||
if (DataLocation.PortableDataLocationInUse())
|
||||
{
|
||||
// When user is using portable but has moved flow to a different location
|
||||
if (IsUsingPortablePath(settings.PluginSettings.PythonExecutablePath, DataLocation.PythonEnvironmentName)
|
||||
&& !settings.PluginSettings.PythonExecutablePath.StartsWith(DataLocation.PortableDataPath))
|
||||
{
|
||||
settings.PluginSettings.PythonExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.PythonExecutablePath);
|
||||
}
|
||||
|
||||
if (IsUsingPortablePath(settings.PluginSettings.NodeExecutablePath, DataLocation.NodeEnvironmentName)
|
||||
&& !settings.PluginSettings.NodeExecutablePath.StartsWith(DataLocation.PortableDataPath))
|
||||
{
|
||||
settings.PluginSettings.NodeExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.NodeExecutablePath);
|
||||
}
|
||||
|
||||
// When user has switched from roaming to portable
|
||||
if (IsUsingRoamingPath(settings.PluginSettings.PythonExecutablePath))
|
||||
{
|
||||
settings.PluginSettings.PythonExecutablePath
|
||||
= settings.PluginSettings.PythonExecutablePath.Replace(DataLocation.RoamingDataPath, DataLocation.PortableDataPath);
|
||||
}
|
||||
|
||||
if (IsUsingRoamingPath(settings.PluginSettings.NodeExecutablePath))
|
||||
{
|
||||
settings.PluginSettings.NodeExecutablePath
|
||||
= settings.PluginSettings.NodeExecutablePath.Replace(DataLocation.RoamingDataPath, DataLocation.PortableDataPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsUsingPortablePath(settings.PluginSettings.PythonExecutablePath, DataLocation.PythonEnvironmentName))
|
||||
settings.PluginSettings.PythonExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.PythonExecutablePath);
|
||||
|
||||
if (IsUsingPortablePath(settings.PluginSettings.NodeExecutablePath, DataLocation.NodeEnvironmentName))
|
||||
settings.PluginSettings.NodeExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.NodeExecutablePath);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsUsingPortablePath(string filePath, string pluginEnvironmentName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return false;
|
||||
|
||||
// DataLocation.PortableDataPath returns the current portable path, this determines if an out
|
||||
// of date path is also a portable path.
|
||||
var portableAppEnvLocation = $"UserData\\{DataLocation.PluginEnvironments}\\{pluginEnvironmentName}";
|
||||
|
||||
return filePath.Contains(portableAppEnvLocation);
|
||||
}
|
||||
|
||||
private static bool IsUsingRoamingPath(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return false;
|
||||
|
||||
return filePath.StartsWith(DataLocation.RoamingDataPath);
|
||||
}
|
||||
|
||||
private static string GetUpdatedEnvironmentPath(string filePath)
|
||||
{
|
||||
var index = filePath.IndexOf(DataLocation.PluginEnvironments);
|
||||
|
||||
// get the substring after "Environments" because we can not determine it dynamically
|
||||
var ExecutablePathSubstring = filePath.Substring(index + DataLocation.PluginEnvironments.Count());
|
||||
return $"{DataLocation.PluginEnvironmentsPath}{ExecutablePathSubstring}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
|
||||
internal class JavaScriptEnvironment : TypeScriptEnvironment
|
||||
{
|
||||
internal override string Language => AllowedLanguage.JavaScript;
|
||||
|
||||
internal JavaScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using Droplex;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
internal class PythonEnvironment : AbstractPluginEnvironment
|
||||
{
|
||||
internal override string Language => AllowedLanguage.Python;
|
||||
|
||||
internal override string EnvName => DataLocation.PythonEnvironmentName;
|
||||
|
||||
internal override string EnvPath => Path.Combine(DataLocation.PluginEnvironmentsPath, EnvName);
|
||||
|
||||
internal override string InstallPath => Path.Combine(EnvPath, "PythonEmbeddable-v3.8.9");
|
||||
|
||||
internal override string ExecutablePath => Path.Combine(InstallPath, "pythonw.exe");
|
||||
|
||||
internal override string FileDialogFilter => "Python|pythonw.exe";
|
||||
|
||||
internal override string PluginsSettingsFilePath { get => PluginSettings.PythonExecutablePath; set => PluginSettings.PythonExecutablePath = value; }
|
||||
|
||||
internal PythonEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
|
||||
internal override void InstallEnvironment()
|
||||
{
|
||||
FilesFolders.RemoveFolderIfExists(InstallPath);
|
||||
|
||||
// Python 3.8.9 is used for Windows 7 compatibility
|
||||
DroplexPackage.Drop(App.python_3_8_9_embeddable, InstallPath).Wait();
|
||||
|
||||
PluginsSettingsFilePath = ExecutablePath;
|
||||
}
|
||||
|
||||
internal override PluginPair CreatePluginPair(string filePath, PluginMetadata metadata)
|
||||
{
|
||||
return new PluginPair
|
||||
{
|
||||
Plugin = new PythonPlugin(filePath),
|
||||
Metadata = metadata
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.IO;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
internal class TypeScriptEnvironment : AbstractPluginEnvironment
|
||||
{
|
||||
internal override string Language => AllowedLanguage.TypeScript;
|
||||
|
||||
internal override string EnvName => DataLocation.NodeEnvironmentName;
|
||||
|
||||
internal override string EnvPath => Path.Combine(DataLocation.PluginEnvironmentsPath, EnvName);
|
||||
|
||||
internal override string InstallPath => Path.Combine(EnvPath, "Node-v16.18.0");
|
||||
internal override string ExecutablePath => Path.Combine(InstallPath, "node-v16.18.0-win-x64\\node.exe");
|
||||
|
||||
internal override string PluginsSettingsFilePath { get => PluginSettings.NodeExecutablePath; set => PluginSettings.NodeExecutablePath = value; }
|
||||
|
||||
internal TypeScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
|
||||
internal override void InstallEnvironment()
|
||||
{
|
||||
FilesFolders.RemoveFolderIfExists(InstallPath);
|
||||
|
||||
DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait();
|
||||
|
||||
PluginsSettingsFilePath = ExecutablePath;
|
||||
}
|
||||
|
||||
internal override PluginPair CreatePluginPair(string filePath, PluginMetadata metadata)
|
||||
{
|
||||
return new PluginPair
|
||||
{
|
||||
Plugin = new NodePlugin(filePath),
|
||||
Metadata = metadata
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Droplex" Version="1.4.1" />
|
||||
<PackageReference Include="Droplex" Version="1.6.0" />
|
||||
<PackageReference Include="FSharp.Core" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.2.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
internal class ExecutablePlugin : JsonRPCPlugin
|
||||
{
|
||||
private readonly ProcessStartInfo _startInfo;
|
||||
public override string SupportedLanguage { get; set; } = AllowedLanguage.Executable;
|
||||
|
||||
public ExecutablePlugin(string filename)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,10 +37,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
protected PluginInitContext context;
|
||||
public const string JsonRPC = "JsonRPC";
|
||||
/// <summary>
|
||||
/// The language this JsonRPCPlugin support
|
||||
/// </summary>
|
||||
public abstract string SupportedLanguage { get; set; }
|
||||
|
||||
protected abstract Task<Stream> RequestAsync(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
|
||||
protected abstract string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
|
||||
|
||||
|
|
|
|||
53
Flow.Launcher.Core/Plugin/NodePlugin.cs
Normal file
53
Flow.Launcher.Core/Plugin/NodePlugin.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Execution of JavaScript & TypeScript plugins
|
||||
/// </summary>
|
||||
internal class NodePlugin : JsonRPCPlugin
|
||||
{
|
||||
private readonly ProcessStartInfo _startInfo;
|
||||
|
||||
public NodePlugin(string filename)
|
||||
{
|
||||
_startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = filename,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
}
|
||||
|
||||
protected override Task<Stream> RequestAsync(JsonRPCRequestModel request, CancellationToken token = default)
|
||||
{
|
||||
_startInfo.ArgumentList[1] = request.ToString();
|
||||
return ExecuteAsync(_startInfo, token);
|
||||
}
|
||||
|
||||
protected override string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default)
|
||||
{
|
||||
// since this is not static, request strings will build up in ArgumentList if index is not specified
|
||||
_startInfo.ArgumentList[1] = rpcRequest.ToString();
|
||||
return Execute(_startInfo);
|
||||
}
|
||||
|
||||
public override async Task InitAsync(PluginInitContext context)
|
||||
{
|
||||
_startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
||||
_startInfo.ArgumentList.Add(string.Empty);
|
||||
await base.InitAsync(context);
|
||||
_startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Core.ExternalPlugins.Environments;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
public static class PluginsLoader
|
||||
{
|
||||
public const string PythonExecutable = "pythonw.exe";
|
||||
|
||||
public static List<PluginPair> Plugins(List<PluginMetadata> metadatas, PluginsSettings settings)
|
||||
{
|
||||
var dotnetPlugins = DotNetPlugins(metadatas);
|
||||
var pythonPlugins = PythonPlugins(metadatas, settings);
|
||||
|
||||
var pythonEnv = new PythonEnvironment(metadatas, settings);
|
||||
var tsEnv = new TypeScriptEnvironment(metadatas, settings);
|
||||
var jsEnv = new JavaScriptEnvironment(metadatas, settings);
|
||||
var pythonPlugins = pythonEnv.Setup();
|
||||
var tsPlugins = tsEnv.Setup();
|
||||
var jsPlugins = jsEnv.Setup();
|
||||
|
||||
var executablePlugins = ExecutablePlugins(metadatas);
|
||||
var plugins = dotnetPlugins.Concat(pythonPlugins).Concat(executablePlugins).ToList();
|
||||
|
||||
var plugins = dotnetPlugins
|
||||
.Concat(pythonPlugins)
|
||||
.Concat(tsPlugins)
|
||||
.Concat(jsPlugins)
|
||||
.Concat(executablePlugins)
|
||||
.ToList();
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
|
@ -108,97 +116,10 @@ namespace Flow.Launcher.Core.Plugin
|
|||
return plugins;
|
||||
}
|
||||
|
||||
public static IEnumerable<PluginPair> PythonPlugins(List<PluginMetadata> source, PluginsSettings settings)
|
||||
{
|
||||
if (!source.Any(o => o.Language.ToUpper() == AllowedLanguage.Python))
|
||||
return new List<PluginPair>();
|
||||
|
||||
if (!string.IsNullOrEmpty(settings.PythonDirectory) && FilesFolders.LocationExists(settings.PythonDirectory))
|
||||
return SetPythonPathForPluginPairs(source, Path.Combine(settings.PythonDirectory, PythonExecutable));
|
||||
|
||||
var pythonPath = string.Empty;
|
||||
|
||||
if (MessageBox.Show("Flow detected you have installed Python plugins, which " +
|
||||
"will need Python to run. Would you like to download Python? " +
|
||||
Environment.NewLine + Environment.NewLine +
|
||||
"Click no if it's already installed, " +
|
||||
"and you will be prompted to select the folder that contains the Python executable",
|
||||
string.Empty, MessageBoxButtons.YesNo) == DialogResult.No
|
||||
&& string.IsNullOrEmpty(settings.PythonDirectory))
|
||||
{
|
||||
var dlg = new FolderBrowserDialog
|
||||
{
|
||||
SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
|
||||
};
|
||||
|
||||
var result = dlg.ShowDialog();
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
string pythonDirectory = dlg.SelectedPath;
|
||||
if (!string.IsNullOrEmpty(pythonDirectory))
|
||||
{
|
||||
pythonPath = Path.Combine(pythonDirectory, PythonExecutable);
|
||||
if (File.Exists(pythonPath))
|
||||
{
|
||||
settings.PythonDirectory = pythonDirectory;
|
||||
Constant.PythonPath = pythonPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Can't find python in given directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var installedPythonDirectory = Path.Combine(DataLocation.DataDirectory(), "PythonEmbeddable");
|
||||
|
||||
// Python 3.8.9 is used for Windows 7 compatibility
|
||||
DroplexPackage.Drop(App.python_3_8_9_embeddable, installedPythonDirectory).Wait();
|
||||
|
||||
pythonPath = Path.Combine(installedPythonDirectory, PythonExecutable);
|
||||
if (FilesFolders.FileExists(pythonPath))
|
||||
{
|
||||
settings.PythonDirectory = installedPythonDirectory;
|
||||
Constant.PythonPath = pythonPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("PluginsLoader",
|
||||
$"Failed to set Python path after Droplex install, {pythonPath} does not exist",
|
||||
"PythonPlugins");
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(settings.PythonDirectory) || string.IsNullOrEmpty(pythonPath))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Unable to set Python executable path, please try from Flow's settings (scroll down to the bottom).");
|
||||
Log.Error("PluginsLoader",
|
||||
$"Not able to successfully set Python path, the PythonDirectory variable is still an empty string.",
|
||||
"PythonPlugins");
|
||||
|
||||
return new List<PluginPair>();
|
||||
}
|
||||
|
||||
return SetPythonPathForPluginPairs(source, pythonPath);
|
||||
}
|
||||
|
||||
private static IEnumerable<PluginPair> SetPythonPathForPluginPairs(List<PluginMetadata> source, string pythonPath)
|
||||
=> source
|
||||
.Where(o => o.Language.ToUpper() == AllowedLanguage.Python)
|
||||
.Select(metadata => new PluginPair
|
||||
{
|
||||
Plugin = new PythonPlugin(pythonPath),
|
||||
Metadata = metadata
|
||||
})
|
||||
.ToList();
|
||||
|
||||
public static IEnumerable<PluginPair> ExecutablePlugins(IEnumerable<PluginMetadata> source)
|
||||
{
|
||||
return source
|
||||
.Where(o => o.Language.ToUpper() == AllowedLanguage.Executable)
|
||||
.Where(o => o.Language.Equals(AllowedLanguage.Executable, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(metadata => new PluginPair
|
||||
{
|
||||
Plugin = new ExecutablePlugin(metadata.ExecuteFilePath), Metadata = metadata
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
|
@ -11,7 +11,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
internal class PythonPlugin : JsonRPCPlugin
|
||||
{
|
||||
private readonly ProcessStartInfo _startInfo;
|
||||
public override string SupportedLanguage { get; set; } = AllowedLanguage.Python;
|
||||
|
||||
public PythonPlugin(string filename)
|
||||
{
|
||||
|
|
@ -46,6 +45,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
protected override string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default)
|
||||
{
|
||||
// since this is not static, request strings will build up in ArgumentList if index is not specified
|
||||
_startInfo.ArgumentList[2] = rpcRequest.ToString();
|
||||
_startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
||||
// TODO: Async Action
|
||||
|
|
|
|||
|
|
@ -144,6 +144,5 @@ namespace Flow.Launcher.Core
|
|||
|
||||
return tips;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace Flow.Launcher.Infrastructure
|
|||
public static readonly string LoadingImgIcon = Path.Combine(ImagesDirectory, "loading.png");
|
||||
|
||||
public static string PythonPath;
|
||||
public static string NodePath;
|
||||
|
||||
public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.svg";
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ namespace Flow.Launcher.Infrastructure.Exception
|
|||
sb.AppendLine($"* IntPtr Length: {IntPtr.Size}");
|
||||
sb.AppendLine($"* x64: {Environment.Is64BitOperatingSystem}");
|
||||
sb.AppendLine($"* Python Path: {Constant.PythonPath}");
|
||||
sb.AppendLine($"* Node Path: {Constant.NodePath}");
|
||||
sb.AppendLine($"* CLR Version: {Environment.Version}");
|
||||
sb.AppendLine($"* Installed .NET Framework: ");
|
||||
foreach (var result in GetFrameworkVersionFromRegistry())
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
|
|
@ -31,5 +27,10 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
|
||||
public static readonly string PluginsDirectory = Path.Combine(DataDirectory(), Constant.Plugins);
|
||||
public static readonly string PluginSettingsDirectory = Path.Combine(DataDirectory(), "Settings", Constant.Plugins);
|
||||
|
||||
public const string PythonEnvironmentName = "Python";
|
||||
public const string NodeEnvironmentName = "Node.js";
|
||||
public const string PluginEnvironments = "Environments";
|
||||
public static readonly string PluginEnvironmentsPath = Path.Combine(DataDirectory(), PluginEnvironments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,34 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
public class PluginsSettings : BaseModel
|
||||
{
|
||||
private string pythonExecutablePath = string.Empty;
|
||||
public string PythonExecutablePath {
|
||||
get { return pythonExecutablePath; }
|
||||
set
|
||||
{
|
||||
pythonExecutablePath = value;
|
||||
Constant.PythonPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
private string nodeExecutablePath = string.Empty;
|
||||
public string NodeExecutablePath
|
||||
{
|
||||
get { return nodeExecutablePath; }
|
||||
set
|
||||
{
|
||||
nodeExecutablePath = value;
|
||||
Constant.NodePath = value;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove. This is backwards compatibility for 1.10.0 release.
|
||||
public string PythonDirectory { get; set; }
|
||||
|
||||
public Dictionary<string, Plugin> Plugins { get; set; } = new Dictionary<string, Plugin>();
|
||||
|
||||
public void UpdatePluginSettings(List<PluginMetadata> metadatas)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
namespace Flow.Launcher.Plugin
|
||||
using System;
|
||||
|
||||
namespace Flow.Launcher.Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Allowed plugin languages
|
||||
|
|
@ -8,34 +10,32 @@
|
|||
/// <summary>
|
||||
/// Python
|
||||
/// </summary>
|
||||
public static string Python
|
||||
{
|
||||
get { return "PYTHON"; }
|
||||
}
|
||||
public const string Python = "Python";
|
||||
|
||||
/// <summary>
|
||||
/// C#
|
||||
/// </summary>
|
||||
public static string CSharp
|
||||
{
|
||||
get { return "CSHARP"; }
|
||||
}
|
||||
public const string CSharp = "CSharp";
|
||||
|
||||
/// <summary>
|
||||
/// F#
|
||||
/// </summary>
|
||||
public static string FSharp
|
||||
{
|
||||
get { return "FSHARP"; }
|
||||
}
|
||||
public const string FSharp = "FSharp";
|
||||
|
||||
/// <summary>
|
||||
/// Standard .exe
|
||||
/// </summary>
|
||||
public static string Executable
|
||||
{
|
||||
get { return "EXECUTABLE"; }
|
||||
}
|
||||
public const string Executable = "Executable";
|
||||
|
||||
/// <summary>
|
||||
/// TypeScript
|
||||
/// </summary>
|
||||
public const string TypeScript = "TypeScript";
|
||||
|
||||
/// <summary>
|
||||
/// JavaScript
|
||||
/// </summary>
|
||||
public const string JavaScript = "JavaScript";
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this language is a .NET language
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
/// <returns></returns>
|
||||
public static bool IsDotNet(string language)
|
||||
{
|
||||
return language.ToUpper() == CSharp
|
||||
|| language.ToUpper() == FSharp;
|
||||
return language.Equals(CSharp, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(FSharp, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -56,8 +56,10 @@
|
|||
public static bool IsAllowed(string language)
|
||||
{
|
||||
return IsDotNet(language)
|
||||
|| language.ToUpper() == Python.ToUpper()
|
||||
|| language.ToUpper() == Executable.ToUpper();
|
||||
|| language.Equals(Python, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(Executable, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(TypeScript, StringComparison.OrdinalIgnoreCase)
|
||||
|| language.Equals(JavaScript, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit;
|
||||
using NUnit;
|
||||
using NUnit.Framework;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
|
@ -16,8 +16,6 @@ namespace Flow.Launcher.Test.Plugins
|
|||
// ReSharper disable once InconsistentNaming
|
||||
internal class JsonRPCPluginTest : JsonRPCPlugin
|
||||
{
|
||||
public override string SupportedLanguage { get; set; } = AllowedLanguage.Executable;
|
||||
|
||||
protected override string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Timers;
|
|||
using System.Windows;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using Flow.Launcher.Core.ExternalPlugins.Environments;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
|
|
@ -61,6 +62,8 @@ namespace Flow.Launcher
|
|||
_settingsVM = new SettingWindowViewModel(_updater, _portable);
|
||||
_settings = _settingsVM.Settings;
|
||||
|
||||
AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
|
||||
|
||||
_alphabet.Initialize(_settings);
|
||||
_stringMatcher = new StringMatcher(_alphabet);
|
||||
StringMatcher.Instance = _stringMatcher;
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ namespace Flow.Launcher.Helper
|
|||
|
||||
public static string DependenciesInfo()
|
||||
{
|
||||
var info = $"\nPython Path: {Constant.PythonPath}";
|
||||
var info = $"\nPython Path: {Constant.PythonPath}\nNode Path: {Constant.NodePath}";
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python bibliotek</system:String>
|
||||
<system:String x:Key="autoUpdates">Autoopdatering</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Vælg</system:String>
|
||||
<system:String x:Key="select">Vælg</system:String>
|
||||
<system:String x:Key="hideOnStartup">Skjul Flow Launcher ved opstart</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Wählen Sie den Dateimanager, der beim Öffnen des Ordners verwendet werden soll.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Standardbrowser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Einstellung für neuen Tab, neues Fenster und dem Privatmodus.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python-Verzeichnis</system:String>
|
||||
<system:String x:Key="autoUpdates">Automatische Aktualisierung</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Auswählen</system:String>
|
||||
<system:String x:Key="select">Auswählen</system:String>
|
||||
<system:String x:Key="hideOnStartup">Verstecke Flow Launcher bei Systemstart</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Statusleistensymbol ausblenden</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -57,11 +57,14 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonFilePath">Python Path</system:String>
|
||||
<system:String x:Key="nodeFilePath">Node.js Path</system:String>
|
||||
<system:String x:Key="selectNodeExecutable">Please select the Node.js executable</system:String>
|
||||
<system:String x:Key="selectPythonExecutable">Please select pythonw.exe</system:String>
|
||||
<system:String x:Key="typingStartEn">Always Start Typing in English Mode</system:String>
|
||||
<system:String x:Key="typingStartEnTooltip">Temporarily change your input method to English mode when activating Flow.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python Directory</system:String>
|
||||
<system:String x:Key="autoUpdates">Auto Update</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Select</system:String>
|
||||
<system:String x:Key="select">Select</system:String>
|
||||
<system:String x:Key="hideOnStartup">Hide Flow Launcher on startup</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
@ -293,7 +296,7 @@
|
|||
<!-- General Notice -->
|
||||
<system:String x:Key="pleaseWait">Please wait...</system:String>
|
||||
|
||||
<!-- update -->
|
||||
<!-- Update -->
|
||||
<system:String x:Key="update_flowlauncher_update_check">Checking for new update</system:String>
|
||||
<system:String x:Key="update_flowlauncher_already_on_latest">You already have the latest Flow Launcher version</system:String>
|
||||
<system:String x:Key="update_flowlauncher_update_found">Update found</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Seleccione el gestor de archivos a utilizar al abrir la carpeta.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Navegador web predeterminado</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Configuración para Nueva Pestaña, Nueva Ventana, Modo Privado.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Directorio de Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Actualización automática</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Seleccionar</system:String>
|
||||
<system:String x:Key="select">Seleccionar</system:String>
|
||||
<system:String x:Key="hideOnStartup">Ocultar Flow Launcher al arrancar el sistema</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Ocultar icono de la bandeja</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Selecciona el administrador de archivos que se desea utilizar para abrir la carpeta.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Navegador web predeterminado</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Configuración para Nueva Pestaña, Nueva Ventana, Modo Privado.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Carpeta de Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Actualización automática</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Seleccionar</system:String>
|
||||
<system:String x:Key="select">Seleccionar</system:String>
|
||||
<system:String x:Key="hideOnStartup">Ocultar Flow Launcher al inicio</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Ocultar icono de la bandeja del sistema</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">Cuando el icono está oculto en la bandeja del sistema, se puede abrir el menú de configuración haciendo clic con el botón derecho en la ventana de búsqueda.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Navigateur web par défaut</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Répertoire de Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Mettre à jour automatiquement</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Sélectionner</system:String>
|
||||
<system:String x:Key="select">Sélectionner</system:String>
|
||||
<system:String x:Key="hideOnStartup">Cacher Flow Launcher au démarrage</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Masquer icône du plateau</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Selezionare il Gestore file da usare all'apertura della cartella.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Browser predefinito</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Impostazione per Nuova scheda, Nuova finestra, Modalità privata.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Cartella Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Aggiornamento automatico</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Seleziona</system:String>
|
||||
<system:String x:Key="select">Seleziona</system:String>
|
||||
<system:String x:Key="hideOnStartup">Nascondi Flow Launcher all'avvio</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Nascondi Icona nell'Area di Notifica</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Pythonのディレクトリ</system:String>
|
||||
<system:String x:Key="autoUpdates">自動更新</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">選択</system:String>
|
||||
<system:String x:Key="select">選択</system:String>
|
||||
<system:String x:Key="hideOnStartup">起動時にFlow Launcherを隠す</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">トレイアイコンを隠す</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">폴더를 열 때 사용할 파일관리자를 선택하세요.</system:String>
|
||||
<system:String x:Key="defaultBrowser">기본 웹 브라우저</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">새 탭, 새 창, 사생활 보호 모드</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python 디렉토리</system:String>
|
||||
<system:String x:Key="autoUpdates">자동 업데이트</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">선택</system:String>
|
||||
<system:String x:Key="select">선택</system:String>
|
||||
<system:String x:Key="hideOnStartup">시작 시 Flow Launcher 숨김</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">트레이 아이콘 숨기기</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">트레이에서 아이콘을 숨길 경우, 검색창 우클릭으로 설정창을 열 수 있습니다.</system:String>
|
||||
|
|
|
|||
|
|
@ -28,9 +28,8 @@
|
|||
<system:String x:Key="LastQueryEmpty">Tøm siste spørring</system:String>
|
||||
<system:String x:Key="maxShowResults">Maks antall resultater vist</system:String>
|
||||
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorer hurtigtaster i fullskjermsmodus</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python-mappe</system:String>
|
||||
<system:String x:Key="autoUpdates">Oppdater automatisk</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Velg</system:String>
|
||||
<system:String x:Key="select">Velg</system:String>
|
||||
<system:String x:Key="hideOnStartup">Skjul Flow Launcher ved oppstart</system:String>
|
||||
|
||||
<!--Setting Plugin-->
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python Directory</system:String>
|
||||
<system:String x:Key="autoUpdates">Auto Update</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Select</system:String>
|
||||
<system:String x:Key="select">Select</system:String>
|
||||
<system:String x:Key="hideOnStartup">Hide Flow Launcher on startup</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Selecteer de bestandsbeheerder voor het openen van de map.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Standaard webbrowser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Instelling voor Nieuw tabblad, Nieuw Venster, Privémodus.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python map</system:String>
|
||||
<system:String x:Key="autoUpdates">Automatische Update</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Selecteer</system:String>
|
||||
<system:String x:Key="select">Selecteer</system:String>
|
||||
<system:String x:Key="hideOnStartup">Verberg Flow Launcher als systeem opstart</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Systeemvakpictogram verbergen</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Wybierz menedżer plików używany do otwierania folderów.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Domyślna przeglądarka</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Ustawienie dla nowej karty, nowego okna i trybu prywatnego.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Folder biblioteki Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Automatyczne aktualizacje</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Wybierz</system:String>
|
||||
<system:String x:Key="select">Wybierz</system:String>
|
||||
<system:String x:Key="hideOnStartup">Uruchamiaj Flow Launcher zminimalizowany</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Ukryj ikonę zasobnika</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Diretório Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Atualizar Automaticamente</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Selecionar</system:String>
|
||||
<system:String x:Key="select">Selecionar</system:String>
|
||||
<system:String x:Key="hideOnStartup">Esconder Flow Launcher na inicialização</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Selecione o gestor de ficheiros utilizado para abrir a página</system:String>
|
||||
<system:String x:Key="defaultBrowser">Navegador web padrão</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Definições para Novo separador, Nova Janela e Modo privado</system:String>
|
||||
<system:String x:Key="pythonDirectory">Diretório Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Atualização automática</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Selecionar</system:String>
|
||||
<system:String x:Key="select">Selecionar</system:String>
|
||||
<system:String x:Key="hideOnStartup">Ocultar Flow Launcher ao arrancar</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Ocultar ícone na bandeja</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">Se o ícone da bandeja estiver oculto, pode abrir as Definições com um clique com o botão direito do rato na caixa de pesquisa.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python Directory</system:String>
|
||||
<system:String x:Key="autoUpdates">Auto Update</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Select</system:String>
|
||||
<system:String x:Key="select">Select</system:String>
|
||||
<system:String x:Key="hideOnStartup">Hide Flow Launcher on startup</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Vyberte správcu súborov, ktorý sa má použiť pri otváraní priečinka.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Predvolený webový prehliadač</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Nastavenie pre novú kartu, nové okno, privátny režim.</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="selectPythonDirectory">Vybrať</system:String>
|
||||
<system:String x:Key="select">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="hideNotifyIconToolTip">Keď je ikona skrytá z oblasti oznámení, nastavenia možno otvoriť kliknutím pravým tlačidlom myši na okno vyhľadávania.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Select the file manager to use when opening the folder.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Default Web Browser</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Setting for New Tab, New Window, Private Mode.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python direktorijum</system:String>
|
||||
<system:String x:Key="autoUpdates">Auto ažuriranje</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Izaberi</system:String>
|
||||
<system:String x:Key="select">Izaberi</system:String>
|
||||
<system:String x:Key="hideOnStartup">Sakrij Flow Launcher pri podizanju sistema</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Hide tray icon</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Klasör açarken kullanılacak dosya yöneticisini seçin.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Varsayılan Tarayıcısı</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Yeni Sekme, Yeni Pencere, Gizli Mod için Ayar.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python Konumu</system:String>
|
||||
<system:String x:Key="autoUpdates">Otomatik Güncelle</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Seç</system:String>
|
||||
<system:String x:Key="select">Seç</system:String>
|
||||
<system:String x:Key="hideOnStartup">Başlangıçta Flow Launcher'u gizle</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Sistem çekmecesi simgesini gizle</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">Виберіть файловий менеджер для використання під час відкриття теки.</system:String>
|
||||
<system:String x:Key="defaultBrowser">Браузер за замовчуванням</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">Налаштування нової вкладки, нового вікна, приватного режиму.</system:String>
|
||||
<system:String x:Key="pythonDirectory">Директорія Python</system:String>
|
||||
<system:String x:Key="autoUpdates">Автоматичне оновлення</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Вибрати</system:String>
|
||||
<system:String x:Key="select">Вибрати</system:String>
|
||||
<system:String x:Key="hideOnStartup">Сховати Flow Launcher при запуску системи</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Приховати значок в системному лотку</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">选择打开文件夹时要使用的文件管理器。</system:String>
|
||||
<system:String x:Key="defaultBrowser">默认浏览器</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">新标签/窗口及隐身模式设置。</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python 路径</system:String>
|
||||
<system:String x:Key="autoUpdates">自动更新</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">选择</system:String>
|
||||
<system:String x:Key="select">选择</system:String>
|
||||
<system:String x:Key="hideOnStartup">系统启动时不显示主窗口</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">隐藏任务栏图标</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">任务栏图标被隐藏时,右键点击搜索窗口即可打开设置菜单。</system:String>
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@
|
|||
<system:String x:Key="defaultFileManagerToolTip">選擇開啟資料夾時要使用的檔案管理器。</system:String>
|
||||
<system:String x:Key="defaultBrowser">預設瀏覽器</system:String>
|
||||
<system:String x:Key="defaultBrowserToolTip">設定新增分頁、視窗和無痕模式。</system:String>
|
||||
<system:String x:Key="pythonDirectory">Python 路徑</system:String>
|
||||
<system:String x:Key="autoUpdates">自動更新</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">選擇</system:String>
|
||||
<system:String x:Key="select">選擇</system:String>
|
||||
<system:String x:Key="hideOnStartup">啟動時不顯示主視窗</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">隱藏任務欄圖標</system:String>
|
||||
<system:String x:Key="hideNotifyIconToolTip">When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.</system:String>
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@
|
|||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Click="btnBrowseFile_Click"
|
||||
Content="{DynamicResource selectPythonDirectory}"
|
||||
Content="{DynamicResource select}"
|
||||
DockPanel.Dock="Right">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="{x:Type Button}">
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@
|
|||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Click="btnBrowseFile_Click"
|
||||
Content="{DynamicResource selectPythonDirectory}"
|
||||
Content="{DynamicResource select}"
|
||||
DockPanel.Dock="Right">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="{x:Type Button}">
|
||||
|
|
|
|||
|
|
@ -919,18 +919,37 @@
|
|||
<Border Margin="0,30,0,0" Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource pythonDirectory}" />
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource pythonFilePath}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="300"
|
||||
Height="34"
|
||||
Text="{Binding Settings.PluginSettings.PythonDirectory, TargetNullValue='No Setting'}" />
|
||||
Text="{Binding Settings.PluginSettings.PythonExecutablePath, TargetNullValue='None'}" />
|
||||
<Button
|
||||
Height="34"
|
||||
Margin="10,0,18,0"
|
||||
Click="OnSelectPythonDirectoryClick"
|
||||
Content="{DynamicResource selectPythonDirectory}" />
|
||||
Click="OnSelectPythonPathClick"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Border Margin="0,4,0,0" Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource nodeFilePath}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="300"
|
||||
Height="34"
|
||||
Text="{Binding Settings.PluginSettings.NodeExecutablePath, TargetNullValue='None'}" />
|
||||
<Button
|
||||
Height="34"
|
||||
Margin="10,0,18,0"
|
||||
Click="OnSelectNodePathClick"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
|
@ -974,7 +993,7 @@
|
|||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource SettingGroupBox}">
|
||||
<Border Margin="0,30,0,0" Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource language}" />
|
||||
|
|
|
|||
|
|
@ -64,31 +64,23 @@ namespace Flow.Launcher
|
|||
InitializePosition();
|
||||
}
|
||||
|
||||
private void OnSelectPythonDirectoryClick(object sender, RoutedEventArgs e)
|
||||
private void OnSelectPythonPathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new FolderBrowserDialog
|
||||
{
|
||||
SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
|
||||
};
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectPythonExecutable"),
|
||||
"Python|pythonw.exe");
|
||||
|
||||
var result = dlg.ShowDialog();
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
string pythonDirectory = dlg.SelectedPath;
|
||||
if (!string.IsNullOrEmpty(pythonDirectory))
|
||||
{
|
||||
var pythonPath = Path.Combine(pythonDirectory, PluginsLoader.PythonExecutable);
|
||||
if (File.Exists(pythonPath))
|
||||
{
|
||||
settings.PluginSettings.PythonDirectory = pythonDirectory;
|
||||
MessageBox.Show("Remember to restart Flow Launcher use new Python path");
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Can't find python in given directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.PythonExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectNodePathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectNodeExecutable"));
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.NodeExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectFileManagerClick(object sender, RoutedEventArgs e)
|
||||
|
|
|
|||
|
|
@ -143,6 +143,29 @@ namespace Flow.Launcher.ViewModel
|
|||
_storage.Save();
|
||||
}
|
||||
|
||||
public string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
var dlg = new System.Windows.Forms.OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
Multiselect = false,
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
Title = title,
|
||||
Filter = filter
|
||||
};
|
||||
|
||||
var result = dlg.ShowDialog();
|
||||
if (result == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
return dlg.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#region general
|
||||
|
||||
// todo a better name?
|
||||
|
|
|
|||
Loading…
Reference in a new issue