using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipelines;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Flow.Launcher.Core.Plugin.JsonRPCV2Models;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin;
using Microsoft.VisualStudio.Threading;
using Nerdbank.Streams;
using StreamJsonRpc;
namespace Flow.Launcher.Core.Plugin
{
internal sealed class PythonPluginV2 : ProcessStreamPluginV2
{
protected override ProcessStartInfo StartInfo { get; set; }
public PythonPluginV2(string filename)
{
StartInfo = new ProcessStartInfo { FileName = filename, };
var path = Path.Combine(Constant.ProgramDirectory, JsonRpc);
StartInfo.EnvironmentVariables["PYTHONPATH"] = path;
StartInfo.EnvironmentVariables["PYTHONDONTWRITEBYTECODE"] = "1";
}
public override async Task InitAsync(PluginInitContext context)
{
// Run .py files via `-c <code>`
if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase))
{
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;
// 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'{libPyWin32LibDirectory}')
sys.path.append(r'{libPyWin32Directory}')
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);
}
protected override MessageHandlerType MessageHandler { get; } = MessageHandlerType.NewLineDelimited;
}
}