fix(tmux): send prompts that start with a hyphen literally

`send-keys -l <text>` keeps parsing options after `-l`, so text starting
with `-` was read as a flag ("unknown flag -x", "invalid flag --") and
never typed. End option parsing with `--` at every send-keys -l site in
sendInput() and sendInputToPane(), as set-buffer already does.
This commit is contained in:
Aamer Akhter committed 2026-10-22 13:26:04 -04:00
1 parent 39077281d1
commit 3489f6cc80
2 files changed
+17 -7

No files matched your search

+13 -3
View File
@@ -3,7 +3,8 @@
* submit (`sendInput`) goes in as ONE bracketed paste. Also `submitsAsKeys()`: a
* single character is typed instead, since a selection dialog ignores a pasted `3`
* and the Enter then confirms the highlighted option. And
* `escapeTmuxTrailingSemicolon()`, which every literal text path runs through.
* `escapeTmuxTrailingSemicolon()`, which every literal text path runs through,
* and the `--` that ends tmux's option parsing before every `send-keys -l` text.
*
* Why: `send-keys -l` typed the text as an unmarked burst, and Codex's paste-burst
* heuristic folded the Enter that followed 50 ms later into the paste as a newline,
@@ -163,13 +164,13 @@ describe('sendInput wiring', () => {
it('types a single-character submit with send-keys -l, so a dialog answer selects', async () => {
const body = await sendInputBody();
const keysBranch = body.slice(body.indexOf('if (submitsAsKeys(textPart))'), body.indexOf('} else {'));
expect(keysBranch).toMatch(/send-keys[^`]*-l \$\{shellescape\(escapeTmuxTrailingSemicolon\(textPart\)\)\}/);
expect(keysBranch).toMatch(/send-keys[^`]*-l -- \$\{shellescape\(escapeTmuxTrailingSemicolon\(textPart\)\)\}/);
expect(keysBranch).not.toContain('pasteText(');
});
it('escapes a trailing ";" on every send-keys -l in sendInput and sendInputToPane', async () => {
const src = await source();
const typed = src.match(/send-keys[^`\n]*-l \$\{[^`\n]*\}/g) ?? [];
const typed = src.match(/send-keys[^`\n]*-l -- \$\{[^`\n]*\}/g) ?? [];
const inSend = [await sendInputBody(), src.slice(src.indexOf('sendInputToPane(muxName'))]
.map((b) => b.slice(0, b.indexOf('\n }\n')))
.join('\n');
@@ -177,4 +178,13 @@ describe('sendInput wiring', () => {
expect(typedHere.length).toBe(4);
for (const cmd of typedHere) expect(cmd).toContain('escapeTmuxTrailingSemicolon(textPart)');
});
// tmux parses an argument after `-l` that starts with `-` as an option, so a
// prompt like `-x hello` or `--help` was refused instead of typed. `--` ends
// option parsing; set-buffer already gets one (buildPasteTextCommands).
it('ends option parsing with -- before the text on every send-keys -l', async () => {
const src = await source();
const literal = src.match(/send-keys -t [^`\n]*\s-l\s[^`\n]*/g) ?? [];
expect(literal.length).toBe(4);
for (const cmd of literal) expect(cmd).toMatch(/\s-l -- \$\{shellescape\(/);
});
});