fix: support standard line editing keys in the CLI inputs, and load PR details from v2 - #117
Conversation
Generated descriptionReplace the CLI’s text inputs with a shared raw-key line editor that powers Topics
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5b01dc09e7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Home, End, Cmd+Left/Right and Alt+Left/Right did nothing (or moved a single character) while chatting with a PR. Ink's `useInput` cannot express these keys: Home and End arrive with an empty `input` and no key flags at all, and Alt, Ctrl and Cmd modifiers on the arrow keys are collapsed into a single `meta` flag. The chat input now subscribes to the raw stdin chunks Ink already reads and maps the escape sequences itself, in a pure module that is unit tested. Supported: Home/End, Cmd+Left/Right, Ctrl+A/Ctrl+E, Alt+Left/Right, Ctrl+Left/Right and Alt+B/Alt+F for word movement, Ctrl+B/Ctrl+F for single characters, forward delete, Alt+Backspace/Ctrl+W, Alt+D, and Ctrl+U/Ctrl+K. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Home/End, Ctrl+A/Ctrl+E, Alt+Arrow and Cmd+Arrow did nothing in the PR search box, the "Chat with PR" box and the PR chat input. Ink's `useInput` cannot express these keys: it reports Home and End as an empty input with no key flags, and collapses Alt and Cmd into one `meta` flag, so Alt+Left was handled as a plain left arrow. Read the raw stdin sequences Ink already emits instead and map them to editing actions: - Home / Ctrl+A / Cmd+Left -> start of line - End / Ctrl+E / Cmd+Right -> end of line - Alt+Arrow, Ctrl+Arrow, Alt+B/F -> one word left/right - Ctrl+W, Alt+Backspace, Ctrl+U, Ctrl+K, Fn+Delete -> readline deletions The parser and buffer operations live in `lib/input/line-editor.ts` and are shared by the chat input and the new `LineInput` component, which replaces `ink-text-input` (arrow keys only) in the menu chat box and adds a real cursor to the PR search box. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5b01dc0 to
e58ffbb
Compare
Chunk boundaries are not key boundaries. Typing quickly coalesces `a` and Left into one `a ESC [ D` chunk, and a paste arrives whole, bracketed by `ESC [ 200~` when the terminal supports it. Neither matched a binding, and the handler dropped any chunk containing ESC, so the typed or pasted text was silently lost. `tokenizeKeySequences` now splits a chunk into one string per keypress before it is mapped, unwrapping bracketed paste. A newline inside pasted text becomes a space, since this is a single line input, but a newline that ends the chunk is still Enter. Also guard `setRawMode` with `isRawModeSupported`, so mounting an input cannot throw where raw mode is unavailable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Opening any pull request failed with "Request failed with status code
405": `fetchPRDetails` was left on `/api/v1/changes/{id}` by the v1 to v2
migration (baz-scm#114), and that route no longer serves GET.
Point it at `/api/v2/changes/{id}` and map the camelCase payload onto
`PullRequestDetails`. The detail endpoint spells its review fields
`reviewState`/`assignee`, unlike the list endpoint's `state`/`reviewer`,
so it needs its own mapper.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Your organization's Advanced Security usage limit has been reached. To continue using Advanced Security reviews, please upgrade your plan or increase your usage limits in your account settings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5a5ce592d8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Three problems the tokenizer brought to light, from review: - A sequence split across two stdin reads (`ESC [` then `D`) had its prefix thrown away and the tail typed as a literal `D`. `tokenizeKeySequences` now returns an incomplete tail as `remainder` and `useKeySequences` holds it for the next chunk, flushing after 30ms so a lone ESC is still the Escape key. A paste that spans chunks waits for its closing marker. - `LineInput` read the buffer from its `value` prop, which the parent has not re-rendered yet part way through a chunk, so `fix\r` submitted the empty value and `ab` + Left + `X` collapsed to `X`. The buffer now lives in a ref, so each key sees the result of the one before it. - Cursor movement and deletion stepped one UTF-16 code unit, splitting emoji and combining marks. Both now step whole graphemes via `Intl.Segmenter`, and the cursor cell renders the whole grapheme. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
baz review |
|
@benglewis does not have a seat in baz. To configure ask an admin to assign them a seat in account settings |
1 similar comment
|
@benglewis does not have a seat in baz. To configure ask an admin to assign them a seat in account settings |
|
baz re review |
|
@benglewis does not have a seat in baz. To configure ask an admin to assign them a seat in account settings |
1 similar comment
|
@benglewis does not have a seat in baz. To configure ask an admin to assign them a seat in account settings |
Problem
The usual command line editing keys were broken in every text input in the CLI:
The cause is that Ink's
useInputcannot express these keys. It normalises every keypress into a small set of flags: Home and End arrive with an emptyinputstring and no flags set, so they are indistinguishable from each other and from noise, and Alt/Ctrl/Cmd on the arrow keys all collapse into a singlemetaflag — so a handler could only ever treatkey.leftArrowas "move one character left".Three separate inputs were affected, and they had three different levels of support:
PullRequestSelector)ReviewMenu)ink-text-input: plain arrows onlyChatInput)meta || ctrlFix
A shared line editor,
src/lib/input/line-editor.ts:tokenizeKeySequences(chunk)— splits a stdin chunk into one string per keypress (chunk boundaries are not key boundaries:a+ Left can arrive as onea ESC [ D, and a paste arrives whole)parseKeySequence(sequence)— escape sequence → semantic editing actionapplyEditorAction(state, action)— action → new{ text, cursor }, returning the same object for no-ops so a re-render can be skippeduseKeySequencessubscribes to the raw stdin chunks Ink already reads, tokenizes them and calls back once per key.LineInputwraps that into a drop-in text input with a real cursor; it replacesink-text-inputin the menu chat box (dependency dropped) and gives the PR search box a cursor for the first time.ChatInputkeeps its own throttled sliding-window rendering and uses the hook directly.Bindings, covering the encodings emitted by Terminal.app, iTerm2, Ghostty, WezTerm, Alacritty, VS Code and tmux:
Enter, Tab, Escape,
?help,/command hints, the@mention autocomplete, ↑↓ list navigation and Ctrl+G merge all behave exactly as before. Unknown escape sequences are ignored instead of risking being typed into the buffer, without swallowing the text around them, and a line break inside pasted text becomes a space rather than submitting half a message.Also: PR loading was broken (405)
Opening any pull request failed with
Request failed with status code 405.fetchPRDetailswas left on/api/v1/changes/{id}by the v1 → v2 migration (#114) and that route no longer serves GET. It now calls/api/v2/changes/{id}and maps the camelCase payload ontoPullRequestDetails— the detail endpoint spells its review fieldsreviewState/assignee, unlike the list endpoint'sstate/reviewer, so it needs its own mapper.Still on v1 and not touched here:
changes/{id}/approve,changes/{id}/merge,changes/{id}/merge-status,discussions/{id}andcomments.merge-statusstill answers 200 on v1; the v2 equivalents of the others reject a change UUID withparams/number, so they need the real v2 signature rather than a guess.Testing
src/lib/input/line-editor.spec.ts— 39 unit tests over tokenizing (including sequences split across chunks), the sequence parser, grapheme boundaries, word boundaries and the editing actions (npm test: 60 passed)ab+ Left +Xin one chunk givesaXb;fix+ CR submitsfix;ESC [thenDas two writes moves left without typing aD; the same with a 300ms gap types theD, as it shoulda😀é👨👩👧the cursor highlights each glyph whole and backspace removes one glyph at a time, including the ZWJ family and the accented letternpm run lint,npm run format:check,npm run buildclean🤖 Generated with Claude Code