Skip to content

Instantly share code, notes, and snippets.

@colelawrence
Created December 24, 2025 09:13
Show Gist options
  • Select an option

  • Save colelawrence/125a32cdc15e004f6729360fe3bec1eb to your computer and use it in GitHub Desktop.

Select an option

Save colelawrence/125a32cdc15e004f6729360fe3bec1eb to your computer and use it in GitHub Desktop.
Edit text in system editor
type PathString = string & { __brand: "path" }
function call<R>(fn: () => R) { return fn(); }
/** TODO: Return null if the user cancels/doesn't save the file (like in git) */
export async function editTextInSystemEditor(originalText: string): Promise<string | null> {
// Create a unique temp directory using Bun's file APIs
const tmpDir = `/tmp/context-edit-${Date.now()}-${Math.random().toString(36).slice(2)}`;
await Bun.$`mkdir -p ${tmpDir}`;
const tmpFile = `${tmpDir}/prompt-edit.txt` as PathString;
try {
await Bun.write(tmpFile, originalText);
const args =
(await guessEditorDarwin(tmpFile)) ||
call(() => {
const editor = process.env.EDITOR || "code";
const vsCodeBased = /^(code|cursor|windsurf|codeium)$|^code\-|/.test(editor);
return vsCodeBased ? [editor, "--wait", tmpFile] : [editor, tmpFile];
});
const child = Bun.spawn(args, {
stdio: ["inherit", "inherit", "inherit"],
});
await child.exited;
let editedText = originalText;
if (child.exitCode === 0) {
editedText = await Bun.file(tmpFile).text();
}
return editedText.trim().length > 0 ? editedText : null;
} finally {
// Clean up temp directory and its contents
await Bun.$`rm -rf ${tmpDir}`;
}
}
async function guessEditorDarwin(filePath: PathString): Promise<null | string[]> {
// guess the editor based on current app (terminal inside one of these products)
const bundleId = process.env.__CFBundleIdentifier;
switch (bundleId) {
case "com.todesktop.230313mzl4w4u92":
return ["cursor", "--wait", filePath];
case "com.microsoft.VSCode":
return ["code", "--wait", filePath];
case "com.microsoft.VSCodeInsiders":
return ["code-insiders", "--wait", filePath];
case "com.exafunction.windsurf":
return ["windsurf", "--wait", filePath];
default:
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment