import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import { assertSuccess } from "@effect/vitest/utils";import * as Crypto from "effect/Crypto";import * as Effect from "effect/Effect";import * as Encoding from "effect/Encoding";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Path from "effect/Path";import * as Sink from "effect/Sink";import * as Stream from "effect/Stream";import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import { isCommandAvailable, launchBrowser, launchEditorProcess, resolveAvailableEditors, resolveBrowserLaunch, resolveEditorLaunch,} from "./externalLauncher.ts"; function encodeUtf16LeBase64(input: string): string { const bytes = new Uint8Array(input.length * 2); for (let index = 0; index < input.length; index += 1) { const code = input.charCodeAt(index); bytes[index * 2] = code & 0xff; bytes[index * 2 + 1] = code >>> 8; } return Encoding.encodeBase64(bytes);} function makeMockDetachedHandle(onUnref: () => void = () => undefined) { return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(1), exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(0)), isRunning: Effect.succeed(true), kill: () => Effect.void, unref: Effect.sync(() => { onUnref(); return Effect.void; }), stdin: Sink.drain, stdout: Stream.empty, stderr: Stream.empty, all: Stream.empty, getInputFd: () => Sink.drain, getOutputFd: () => Stream.empty, });} it.layer(NodeServices.layer)("resolveEditorLaunch", (it) => { it.effect("returns commands for command-based editors", () => Effect.gen(function* () { const antigravityLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "antigravity" }, "darwin", { PATH: "" }, ); assert.deepEqual(antigravityLaunch, { command: "agy", args: ["/tmp/workspace"], }); const cursorLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(cursorLaunch, { command: "cursor", args: ["/tmp/workspace"], }); const traeLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "trae" }, "darwin", ); assert.deepEqual(traeLaunch, { command: "trae", args: ["/tmp/workspace"], }); const kiroLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "kiro" }, "darwin", { PATH: "" }, ); assert.deepEqual(kiroLaunch, { command: "kiro", args: ["ide", "/tmp/workspace"], }); const vscodeLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscode" }, "darwin", { PATH: "" }, ); assert.deepEqual(vscodeLaunch, { command: "code", args: ["/tmp/workspace"], }); const vscodeInsidersLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscode-insiders" }, "darwin", ); assert.deepEqual(vscodeInsidersLaunch, { command: "code-insiders", args: ["/tmp/workspace"], }); const vscodiumLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscodium" }, "darwin", ); assert.deepEqual(vscodiumLaunch, { command: "codium", args: ["/tmp/workspace"], }); const zedLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLaunch, { command: "zed", args: ["/tmp/workspace"], }); const ideaLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLaunch, { command: "idea", args: ["/tmp/workspace"], }); const aquaLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "aqua" }, "darwin", ); assert.deepEqual(aquaLaunch, { command: "aqua", args: ["/tmp/workspace"], }); const clionLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "clion" }, "darwin", ); assert.deepEqual(clionLaunch, { command: "clion", args: ["/tmp/workspace"], }); const datagripLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "datagrip" }, "darwin", ); assert.deepEqual(datagripLaunch, { command: "datagrip", args: ["/tmp/workspace"], }); const dataspellLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "dataspell" }, "darwin", ); assert.deepEqual(dataspellLaunch, { command: "dataspell", args: ["/tmp/workspace"], }); const golandLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "goland" }, "darwin", ); assert.deepEqual(golandLaunch, { command: "goland", args: ["/tmp/workspace"], }); const phpstormLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "phpstorm" }, "darwin", ); assert.deepEqual(phpstormLaunch, { command: "phpstorm", args: ["/tmp/workspace"], }); const pycharmLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "pycharm" }, "darwin", ); assert.deepEqual(pycharmLaunch, { command: "pycharm", args: ["/tmp/workspace"], }); const riderLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rider" }, "darwin", ); assert.deepEqual(riderLaunch, { command: "rider", args: ["/tmp/workspace"], }); const rubymineLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rubymine" }, "darwin", ); assert.deepEqual(rubymineLaunch, { command: "rubymine", args: ["/tmp/workspace"], }); const rustroverLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rustrover" }, "darwin", ); assert.deepEqual(rustroverLaunch, { command: "rustrover", args: ["/tmp/workspace"], }); const webstormLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "webstorm" }, "darwin", ); assert.deepEqual(webstormLaunch, { command: "webstorm", args: ["/tmp/workspace"], }); }), ); it.effect("applies launch-style-specific navigation arguments", () => Effect.gen(function* () { const lineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(lineOnly, { command: "cursor", args: ["--goto", "/tmp/workspace/AGENTS.md:48"], }); const lineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(lineAndColumn, { command: "cursor", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const traeLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "trae" }, "darwin", ); assert.deepEqual(traeLineAndColumn, { command: "trae", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const kiroLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "kiro" }, "darwin", { PATH: "" }, ); assert.deepEqual(kiroLineAndColumn, { command: "kiro", args: ["ide", "--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodeLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode" }, "darwin", { PATH: "" }, ); assert.deepEqual(vscodeLineAndColumn, { command: "code", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodeInsidersLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode-insiders" }, "darwin", ); assert.deepEqual(vscodeInsidersLineAndColumn, { command: "code-insiders", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodiumLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscodium" }, "darwin", ); assert.deepEqual(vscodiumLineAndColumn, { command: "codium", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const zedLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLineAndColumn, { command: "zed", args: ["/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const zedLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLineOnly, { command: "zed", args: ["/tmp/workspace/AGENTS.md:48"], }); const ideaLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLineOnly, { command: "idea", args: ["--line", "48", "/tmp/workspace/AGENTS.md"], }); const ideaLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLineAndColumn, { command: "idea", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const aquaLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "aqua" }, "darwin", ); assert.deepEqual(aquaLineAndColumn, { command: "aqua", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const clionLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "clion" }, "darwin", ); assert.deepEqual(clionLineAndColumn, { command: "clion", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const datagripLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "datagrip" }, "darwin", ); assert.deepEqual(datagripLineAndColumn, { command: "datagrip", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const dataspellLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "dataspell" }, "darwin", ); assert.deepEqual(dataspellLineAndColumn, { command: "dataspell", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const golandLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "goland" }, "darwin", ); assert.deepEqual(golandLineAndColumn, { command: "goland", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const phpstormLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "phpstorm" }, "darwin", ); assert.deepEqual(phpstormLineAndColumn, { command: "phpstorm", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const pycharmLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "pycharm" }, "darwin", ); assert.deepEqual(pycharmLineAndColumn, { command: "pycharm", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const riderLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rider" }, "darwin", ); assert.deepEqual(riderLineAndColumn, { command: "rider", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const rubymineLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rubymine" }, "darwin", ); assert.deepEqual(rubymineLineAndColumn, { command: "rubymine", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const rustroverLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rustrover" }, "darwin", ); assert.deepEqual(rustroverLineAndColumn, { command: "rustrover", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const webstormLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "webstorm" }, "darwin", ); assert.deepEqual(webstormLineOnly, { command: "webstorm", args: ["--line", "48", "/tmp/workspace/AGENTS.md"], }); }), ); it.effect("falls back to zeditor when zed is not installed", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-external-launcher-test-" }); yield* fs.writeFileString(path.join(dir, "zeditor"), "#!/bin/sh\nexit 0\n"); yield* fs.chmod(path.join(dir, "zeditor"), 0o755); const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", { PATH: dir, }); assert.deepEqual(result, { command: "zeditor", args: ["/tmp/workspace"], }); }), ); it.effect("falls back to the primary command when no alias is installed", () => Effect.gen(function* () { const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", { PATH: "", }); assert.deepEqual(result, { command: "zed", args: ["/tmp/workspace"], }); }), ); it.effect("maps file-manager editor to OS open commands", () => Effect.gen(function* () { const launch1 = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "file-manager" }, "darwin", { PATH: "" }, ); assert.deepEqual(launch1, { command: "open", args: ["/tmp/workspace"], }); const launch2 = yield* resolveEditorLaunch( { cwd: "C:\\workspace", editor: "file-manager" }, "win32", { PATH: "" }, ); assert.deepEqual(launch2, { command: "explorer", args: ["C:\\workspace"],Lines 1–500 of 804. Load more
import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; import { assertSuccess } from "@effect/vitest/utils"; import * as Crypto from "effect/Crypto"; import * as Effect from "effect/Effect"; import * as Encoding from "effect/Encoding"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Path from "effect/Path"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import { isCommandAvailable, launchBrowser, launchEditorProcess, resolveAvailableEditors, resolveBrowserLaunch, resolveEditorLaunch, } from "./externalLauncher.ts"; function encodeUtf16LeBase64(input: string): string { const bytes = new Uint8Array(input.length * 2); for (let index = 0; index < input.length; index += 1) { const code = input.charCodeAt(index); bytes[index * 2] = code & 0xff; bytes[index * 2 + 1] = code >>> 8; } return Encoding.encodeBase64(bytes); } function makeMockDetachedHandle(onUnref: () => void = () => undefined) { return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(1), exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(0)), isRunning: Effect.succeed(true), kill: () => Effect.void, unref: Effect.sync(() => { onUnref(); return Effect.void; }), stdin: Sink.drain, stdout: Stream.empty, stderr: Stream.empty, all: Stream.empty, getInputFd: () => Sink.drain, getOutputFd: () => Stream.empty, }); } it.layer(NodeServices.layer)("resolveEditorLaunch", (it) => { it.effect("returns commands for command-based editors", () => Effect.gen(function* () { const antigravityLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "antigravity" }, "darwin", { PATH: "" }, ); assert.deepEqual(antigravityLaunch, { command: "agy", args: ["/tmp/workspace"], }); const cursorLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(cursorLaunch, { command: "cursor", args: ["/tmp/workspace"], }); const traeLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "trae" }, "darwin", ); assert.deepEqual(traeLaunch, { command: "trae", args: ["/tmp/workspace"], }); const kiroLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "kiro" }, "darwin", { PATH: "" }, ); assert.deepEqual(kiroLaunch, { command: "kiro", args: ["ide", "/tmp/workspace"], }); const vscodeLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscode" }, "darwin", { PATH: "" }, ); assert.deepEqual(vscodeLaunch, { command: "code", args: ["/tmp/workspace"], }); const vscodeInsidersLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscode-insiders" }, "darwin", ); assert.deepEqual(vscodeInsidersLaunch, { command: "code-insiders", args: ["/tmp/workspace"], }); const vscodiumLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscodium" }, "darwin", ); assert.deepEqual(vscodiumLaunch, { command: "codium", args: ["/tmp/workspace"], }); const zedLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLaunch, { command: "zed", args: ["/tmp/workspace"], }); const ideaLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLaunch, { command: "idea", args: ["/tmp/workspace"], }); const aquaLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "aqua" }, "darwin", ); assert.deepEqual(aquaLaunch, { command: "aqua", args: ["/tmp/workspace"], }); const clionLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "clion" }, "darwin", ); assert.deepEqual(clionLaunch, { command: "clion", args: ["/tmp/workspace"], }); const datagripLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "datagrip" }, "darwin", ); assert.deepEqual(datagripLaunch, { command: "datagrip", args: ["/tmp/workspace"], }); const dataspellLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "dataspell" }, "darwin", ); assert.deepEqual(dataspellLaunch, { command: "dataspell", args: ["/tmp/workspace"], }); const golandLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "goland" }, "darwin", ); assert.deepEqual(golandLaunch, { command: "goland", args: ["/tmp/workspace"], }); const phpstormLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "phpstorm" }, "darwin", ); assert.deepEqual(phpstormLaunch, { command: "phpstorm", args: ["/tmp/workspace"], }); const pycharmLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "pycharm" }, "darwin", ); assert.deepEqual(pycharmLaunch, { command: "pycharm", args: ["/tmp/workspace"], }); const riderLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rider" }, "darwin", ); assert.deepEqual(riderLaunch, { command: "rider", args: ["/tmp/workspace"], }); const rubymineLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rubymine" }, "darwin", ); assert.deepEqual(rubymineLaunch, { command: "rubymine", args: ["/tmp/workspace"], }); const rustroverLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "rustrover" }, "darwin", ); assert.deepEqual(rustroverLaunch, { command: "rustrover", args: ["/tmp/workspace"], }); const webstormLaunch = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "webstorm" }, "darwin", ); assert.deepEqual(webstormLaunch, { command: "webstorm", args: ["/tmp/workspace"], }); }), ); it.effect("applies launch-style-specific navigation arguments", () => Effect.gen(function* () { const lineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(lineOnly, { command: "cursor", args: ["--goto", "/tmp/workspace/AGENTS.md:48"], }); const lineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "cursor" }, "darwin", { PATH: "" }, ); assert.deepEqual(lineAndColumn, { command: "cursor", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const traeLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "trae" }, "darwin", ); assert.deepEqual(traeLineAndColumn, { command: "trae", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const kiroLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "kiro" }, "darwin", { PATH: "" }, ); assert.deepEqual(kiroLineAndColumn, { command: "kiro", args: ["ide", "--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodeLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode" }, "darwin", { PATH: "" }, ); assert.deepEqual(vscodeLineAndColumn, { command: "code", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodeInsidersLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode-insiders" }, "darwin", ); assert.deepEqual(vscodeInsidersLineAndColumn, { command: "code-insiders", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const vscodiumLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscodium" }, "darwin", ); assert.deepEqual(vscodiumLineAndColumn, { command: "codium", args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const zedLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLineAndColumn, { command: "zed", args: ["/tmp/workspace/src/process/externalLauncher.ts:71:5"], }); const zedLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "zed" }, "darwin", { PATH: "" }, ); assert.deepEqual(zedLineOnly, { command: "zed", args: ["/tmp/workspace/AGENTS.md:48"], }); const ideaLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLineOnly, { command: "idea", args: ["--line", "48", "/tmp/workspace/AGENTS.md"], }); const ideaLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "idea" }, "darwin", ); assert.deepEqual(ideaLineAndColumn, { command: "idea", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const aquaLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "aqua" }, "darwin", ); assert.deepEqual(aquaLineAndColumn, { command: "aqua", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const clionLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "clion" }, "darwin", ); assert.deepEqual(clionLineAndColumn, { command: "clion", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const datagripLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "datagrip" }, "darwin", ); assert.deepEqual(datagripLineAndColumn, { command: "datagrip", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const dataspellLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "dataspell" }, "darwin", ); assert.deepEqual(dataspellLineAndColumn, { command: "dataspell", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const golandLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "goland" }, "darwin", ); assert.deepEqual(golandLineAndColumn, { command: "goland", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const phpstormLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "phpstorm" }, "darwin", ); assert.deepEqual(phpstormLineAndColumn, { command: "phpstorm", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const pycharmLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "pycharm" }, "darwin", ); assert.deepEqual(pycharmLineAndColumn, { command: "pycharm", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const riderLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rider" }, "darwin", ); assert.deepEqual(riderLineAndColumn, { command: "rider", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const rubymineLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rubymine" }, "darwin", ); assert.deepEqual(rubymineLineAndColumn, { command: "rubymine", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const rustroverLineAndColumn = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rustrover" }, "darwin", ); assert.deepEqual(rustroverLineAndColumn, { command: "rustrover", args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"], }); const webstormLineOnly = yield* resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "webstorm" }, "darwin", ); assert.deepEqual(webstormLineOnly, { command: "webstorm", args: ["--line", "48", "/tmp/workspace/AGENTS.md"], }); }), ); it.effect("falls back to zeditor when zed is not installed", () => Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-external-launcher-test-" }); yield* fs.writeFileString(path.join(dir, "zeditor"), "#!/bin/sh\nexit 0\n"); yield* fs.chmod(path.join(dir, "zeditor"), 0o755); const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", { PATH: dir, }); assert.deepEqual(result, { command: "zeditor", args: ["/tmp/workspace"], }); }), ); it.effect("falls back to the primary command when no alias is installed", () => Effect.gen(function* () { const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", { PATH: "", }); assert.deepEqual(result, { command: "zed", args: ["/tmp/workspace"], }); }), ); it.effect("maps file-manager editor to OS open commands", () => Effect.gen(function* () { const launch1 = yield* resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "file-manager" }, "darwin", { PATH: "" }, ); assert.deepEqual(launch1, { command: "open", args: ["/tmp/workspace"], }); const launch2 = yield* resolveEditorLaunch( { cwd: "C:\\workspace", editor: "file-manager" }, "win32", { PATH: "" }, ); assert.deepEqual(launch2, { command: "explorer", args: ["C:\\workspace"],