mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 21:32:40 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e66773b7d0 |
@@ -1,7 +1,9 @@
|
||||
import type { SpawnOptions } from "node:child_process";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { listAvailableEditorTargets, openEditorTarget } from "./registry.js";
|
||||
import { createEditorTargetRuntime } from "./runtime.js";
|
||||
import { zedTarget } from "./targets/zed.js";
|
||||
|
||||
interface SpawnRecord {
|
||||
command: string;
|
||||
@@ -10,6 +12,23 @@ interface SpawnRecord {
|
||||
unrefed: boolean;
|
||||
}
|
||||
|
||||
function recordSpawns(records: SpawnRecord[]) {
|
||||
return (command: string, args: string[], options: SpawnOptions) => {
|
||||
const record = { command, args, options, unrefed: false };
|
||||
records.push(record);
|
||||
const child = {
|
||||
once(event: "error" | "spawn", handler: (error?: Error) => void) {
|
||||
if (event === "spawn") queueMicrotask(() => handler());
|
||||
return child;
|
||||
},
|
||||
unref() {
|
||||
record.unrefed = true;
|
||||
},
|
||||
};
|
||||
return child;
|
||||
};
|
||||
}
|
||||
|
||||
describe("editor target runtime", () => {
|
||||
it("resolves command aliases and safely launches Windows command scripts", async () => {
|
||||
const records: SpawnRecord[] = [];
|
||||
@@ -20,20 +39,7 @@ describe("editor target runtime", () => {
|
||||
ELECTRON_RUN_AS_NODE: "1",
|
||||
},
|
||||
pathExists: (targetPath) => targetPath === "C:/Program Files/Editors & Tools/bin/code.cmd",
|
||||
spawn: (command, args, options) => {
|
||||
const record = { command, args, options, unrefed: false };
|
||||
records.push(record);
|
||||
const child = {
|
||||
once(event: "error" | "spawn", handler: (error?: Error) => void) {
|
||||
if (event === "spawn") queueMicrotask(() => handler());
|
||||
return child;
|
||||
},
|
||||
unref() {
|
||||
record.unrefed = true;
|
||||
},
|
||||
};
|
||||
return child;
|
||||
},
|
||||
spawn: recordSpawns(records),
|
||||
});
|
||||
|
||||
const command = runtime.resolveCommand(["missing", "code"]);
|
||||
@@ -57,4 +63,32 @@ describe("editor target runtime", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["system", "/var/lib/flatpak/exports/bin/dev.zed.Zed"],
|
||||
["user", "/home/dev/.local/share/flatpak/exports/bin/dev.zed.Zed"],
|
||||
])("finds and opens Zed from a %s Flatpak install on Linux", async (_scope, flatpakExport) => {
|
||||
const records: SpawnRecord[] = [];
|
||||
const existingPaths = new Set([flatpakExport, "/repo", "/repo/src/app.ts"]);
|
||||
const runtime = createEditorTargetRuntime({
|
||||
platform: "linux",
|
||||
env: { PATH: "/usr/local/bin:/usr/bin:/bin" },
|
||||
homeDirectory: "/home/dev",
|
||||
pathExists: (targetPath) => existingPaths.has(targetPath),
|
||||
spawn: recordSpawns(records),
|
||||
loadIcon: async (fileName) => ({ kind: "image", dataUrl: fileName }),
|
||||
});
|
||||
|
||||
const targets = await listAvailableEditorTargets(runtime, [zedTarget]);
|
||||
expect(targets.map((target) => target.id)).toEqual(["zed"]);
|
||||
|
||||
await openEditorTarget(
|
||||
{ editorId: "zed", workspacePath: "/repo", filePath: "/repo/src/app.ts", line: 3 },
|
||||
runtime,
|
||||
[zedTarget],
|
||||
);
|
||||
expect(records.map(({ command, args }) => ({ command, args }))).toEqual([
|
||||
{ command: flatpakExport, args: ["/repo", "/repo/src/app.ts:3"] },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,10 +56,28 @@ function isAbsolutePath(value: string, platform: NodeJS.Platform): boolean {
|
||||
return platform === "win32" ? win32.isAbsolute(value) : posix.isAbsolute(value);
|
||||
}
|
||||
|
||||
// Flatpak exports app launchers here, but does not put these directories on PATH.
|
||||
function flatpakExportDirectories(env: NodeJS.ProcessEnv, homeDirectory: string): string[] {
|
||||
const userDataDirectory = env.XDG_DATA_HOME || `${homeDirectory}/.local/share`;
|
||||
return [`${userDataDirectory}/flatpak/exports/bin`, "/var/lib/flatpak/exports/bin"];
|
||||
}
|
||||
|
||||
function commandSearchDirectories(input: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
platform: NodeJS.Platform;
|
||||
homeDirectory: string;
|
||||
}): string[] {
|
||||
const pathValue = input.env.PATH ?? input.env.Path ?? input.env.path ?? "";
|
||||
const pathDelimiter = input.platform === "win32" ? ";" : ":";
|
||||
const directories = pathValue.split(pathDelimiter).filter(Boolean);
|
||||
if (input.platform !== "linux") return directories;
|
||||
return [...directories, ...flatpakExportDirectories(input.env, input.homeDirectory)];
|
||||
}
|
||||
|
||||
function resolveExecutable(
|
||||
commands: readonly string[],
|
||||
input: {
|
||||
env: NodeJS.ProcessEnv;
|
||||
searchDirectories: readonly string[];
|
||||
pathExists: (path: string) => boolean;
|
||||
platform: NodeJS.Platform;
|
||||
},
|
||||
@@ -69,10 +87,7 @@ function resolveExecutable(
|
||||
return command;
|
||||
}
|
||||
|
||||
const pathValue = input.env.PATH ?? input.env.Path ?? input.env.path ?? "";
|
||||
const pathDelimiter = input.platform === "win32" ? ";" : ":";
|
||||
for (const directory of pathValue.split(pathDelimiter)) {
|
||||
if (!directory) continue;
|
||||
for (const directory of input.searchDirectories) {
|
||||
const candidate = `${directory}/${command}`;
|
||||
if (input.platform !== "win32") {
|
||||
if (input.pathExists(candidate)) return candidate;
|
||||
@@ -140,7 +155,12 @@ export function createEditorTargetRuntime(
|
||||
env,
|
||||
pathExists,
|
||||
isAbsolutePath: (targetPath) => isAbsolutePath(targetPath, platform),
|
||||
resolveCommand: (commands) => resolveExecutable(commands, { env, pathExists, platform }),
|
||||
resolveCommand: (commands) =>
|
||||
resolveExecutable(commands, {
|
||||
searchDirectories: commandSearchDirectories({ env, platform, homeDirectory }),
|
||||
pathExists,
|
||||
platform,
|
||||
}),
|
||||
async spawnDetached({ command, args }) {
|
||||
const commandScript = isWindowsCommandScript(command, platform);
|
||||
const launchCommand = commandScript ? escapeWindowsCmdValue(command) : command;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EditorTarget, EditorTargetLaunchInput } from "../target.js";
|
||||
|
||||
const COMMANDS = ["zed", "zeditor"] as const;
|
||||
const COMMANDS = ["zed", "zeditor", "dev.zed.Zed"] as const;
|
||||
|
||||
function location(input: EditorTargetLaunchInput): string {
|
||||
if (!input.line) return input.filePath!;
|
||||
|
||||
Reference in New Issue
Block a user