feat(tui): implement ADR-0049 bracketed paste support in settings overlay - #72
Merged
Merged
Conversation
Co-authored-by: Justin Wilkin <justin@entr.net.au>
…ution Co-authored-by: Justin Wilkin <justin@entr.net.au>
Contributor
There was a problem hiding this comment.
Pull request overview
Implements ADR-0049 by adding bracketed paste handling to the TUI settings overlay so users can paste multi-character values (API keys, base URLs, etc.) into dialog fields.
Changes:
- Route
tea.KeyMsg{Paste: true}events to a new paste handler for dialog fields. - Replace the single-character guard with
isPrintableInput()and add helpers for paste sanitization and printable input detection. - Add unit tests covering
isPrintableInputand bracketed paste behaviors.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| pkg/executor/tui/overlay/settings.go | Adds paste routing + paste insertion helper + printable-input gating for dialog input. |
| pkg/executor/tui/overlay/settings_test.go | Adds new tests for printable input gating and bracketed paste scenarios. |
| docs/adr/0049-tui-bracketed-paste-support.md | Updates ADR status/decision details to reflect the implemented approach for Bubble Tea v1.3.10. |
Comments suppressed due to low confidence (1)
docs/adr/0049-tui-bracketed-paste-support.md:277
- ADR note says
unicodeis already imported insettings.goand no new imports are needed, but this PR explicitly adds theunicodeimport. Consider updating this line to avoid contradicting the implementation/diff (or remove the import-related note entirely).
In Bubble Tea v1.3.10, there is no exported `tea.PasteMsg` type. The `keyMsg.Paste` check in `handleDialogInput` must appear **before** the key-switch so pasted content is never dispatched to the normal key handlers.
`strings` and `unicode` packages are already imported in `settings.go` — no new imports needed.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…mentation - Replace isPrintableInput() guard in handleDialogCharInput with keyMsg.Type == tea.KeyRunes check; avoids inserting Bubble Tea control-key strings (ctrl+v, ctrl+c, alt+x) as literal text - Use keyMsg.Runes directly for character insertion (avoids keyMsg.String() which formats multi-key events as 'ctrl+x' etc.) - Replace handleDialogPaste whitelist (\n\r\t) with unicode.IsPrint filter so escape sequences and other control chars are also stripped - Fix maxLength enforcement in both handleDialogCharInput and handleDialogPaste to use rune counts (len([]rune(...))) not byte counts - Remove isPrintableInput() helper (no longer needed) - Replace TestIsPrintableInput with TestInputDialog_CharInput (5 subtests) - Add TestInputDialog_BracketedPaste: escape-sequence stripping and rune-based maxLength subtests (11 subtests total, all pass)
justinwilkin
added a commit
that referenced
this pull request
Mar 2, 2026
…rlay (#72) * fix(tui/overlay): handle bracketed paste input in settings dialog Co-authored-by: Justin Wilkin <justin@entr.net.au> * docs(adr): update ADR-0049 to reflect implemented bracketed paste solution Co-authored-by: Justin Wilkin <justin@entr.net.au> * fix(tui/overlay): address PR review comments on bracketed paste implementation - Replace isPrintableInput() guard in handleDialogCharInput with keyMsg.Type == tea.KeyRunes check; avoids inserting Bubble Tea control-key strings (ctrl+v, ctrl+c, alt+x) as literal text - Use keyMsg.Runes directly for character insertion (avoids keyMsg.String() which formats multi-key events as 'ctrl+x' etc.) - Replace handleDialogPaste whitelist (\n\r\t) with unicode.IsPrint filter so escape sequences and other control chars are also stripped - Fix maxLength enforcement in both handleDialogCharInput and handleDialogPaste to use rune counts (len([]rune(...))) not byte counts - Remove isPrintableInput() helper (no longer needed) - Replace TestIsPrintableInput with TestInputDialog_CharInput (5 subtests) - Add TestInputDialog_BracketedPaste: escape-sequence stripping and rune-based maxLength subtests (11 subtests total, all pass) --------- Co-authored-by: anvxl <anvxl@entr.net.au>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements ADR-0049 — bracketed paste support for the TUI settings dialog fields.
Problem
The settings overlay only accepted single-character key events. Multi-character paste events (from the terminal's bracketed paste mode) were silently discarded, making it impossible to paste API keys, base URLs, or other long strings into dialog fields.
Solution
Bubble Tea v1.3.10 delivers bracketed paste as a
tea.KeyMsgwithPaste: trueandType: KeyRunes— the pasted content is inkeyMsg.Runes. Bracketed paste is enabled by default in v1.3.10; no program option changes were needed.Changes
pkg/executor/tui/overlay/settings.gokeyMsg.Pastebranch inhandleDialogInput— routes paste events to the newhandleDialogPastebefore they hit the key-switchlen(keyMsg.String()) == 1guard inhandleDialogCharInputwithisPrintableInput()— correctly rejects control sequences while accepting multi-rune charactershandleDialogPaste(text string)— strips\n,\r,\t(password managers append trailing newlines), respectsmaxLengthvia rune-aware slicing, clearserrorMsgon successisPrintableInput(s string) bool— usesunicode.IsPrintto gate single-char inputpkg/executor/tui/overlay/settings_test.goisPrintableInput, 9 for bracketed paste scenarios (basic paste, append, newline/tab stripping, maxLength, password fields, error clearing)Test Results
All 22 new tests pass. Full suite green, no regressions.
Known Limitations
Ctrl+V on terminals without bracketed paste support still delivers a raw key event and will not trigger paste behaviour. Supported terminals: iTerm2, Alacritty, kitty, Windows Terminal, GNOME Terminal, tmux ≥ 2.6.