({
basePath,
file,
renderer,
selectedHunk,
}: {
basePath?: string;
file: DiffFile | undefined;
renderer: Pick<CliRenderer, "suspend" | "resume" | "isDestroyed">;
selectedHunk: DiffFile["metadata"]["hunks"][number] | undefined;
})
| 78 | |
| 79 | /** Open the selected file in $EDITOR, suspending TUI for terminal editors. */ |
| 80 | export function openSelectedFileInEditor({ |
| 81 | basePath, |
| 82 | file, |
| 83 | renderer, |
| 84 | selectedHunk, |
| 85 | }: { |
| 86 | basePath?: string; |
| 87 | file: DiffFile | undefined; |
| 88 | renderer: Pick<CliRenderer, "suspend" | "resume" | "isDestroyed">; |
| 89 | selectedHunk: DiffFile["metadata"]["hunks"][number] | undefined; |
| 90 | }) { |
| 91 | if (!file) { |
| 92 | return "No file selected."; |
| 93 | } |
| 94 | |
| 95 | const editor = process.env.EDITOR?.trim(); |
| 96 | if (!editor) { |
| 97 | return "$EDITOR is not set."; |
| 98 | } |
| 99 | |
| 100 | const absolutePath = resolveEditableFilePath(file.path, basePath); |
| 101 | if (!existsSync(absolutePath)) { |
| 102 | return `Cannot edit ${file.path}: file does not exist on disk.`; |
| 103 | } |
| 104 | |
| 105 | const line = Math.max(1, selectedLine(file, selectedHunk)); |
| 106 | const command = buildEditorCommand({ |
| 107 | editor, |
| 108 | filePath: absolutePath, |
| 109 | line, |
| 110 | }); |
| 111 | |
| 112 | const shouldSuspend = shouldSuspendForEditor(editor); |
| 113 | if (shouldSuspend) { |
| 114 | renderer.suspend(); |
| 115 | } |
| 116 | |
| 117 | let exitCode = 0; |
| 118 | let failureMessage: string | null = null; |
| 119 | try { |
| 120 | const result = Bun.spawnSync([command.command, ...command.args], { |
| 121 | stdin: "inherit", |
| 122 | stdout: "inherit", |
| 123 | stderr: "inherit", |
| 124 | }); |
| 125 | exitCode = result.exitCode; |
| 126 | } catch (error) { |
| 127 | failureMessage = error instanceof Error ? error.message : String(error); |
| 128 | } |
| 129 | |
| 130 | if (shouldSuspend && !renderer.isDestroyed) { |
| 131 | renderer.resume(); |
| 132 | } |
| 133 | |
| 134 | if (failureMessage) { |
| 135 | return `Failed to launch editor: ${failureMessage}`; |
| 136 | } |
| 137 |
no test coverage detected