Remove the !autocompleteState guard so CURSOR_MARKER is still emitted
while the slash-command menu is visible. This lets the TUI position the
hardware cursor correctly, which fixes IME candidate-window placement
for CJK input methods.
* feat(tui): treat paste markers as atomic segments in editor
Paste markers like `[paste #1 +123 lines]` are now treated as single
atomic units for cursor movement, word navigation, deletion, and
wrapping. Only markers with valid paste IDs (present in the editor's
pastes Map) are treated atomically.
* fix(tui): word-wrap oversized atomic segments in editor
* feat(tui): extract KillRing and UndoStack, add to Input
Extract kill ring and undo logic from Editor into reusable classes:
- KillRing: ring buffer with accumulation for consecutive kills
- UndoStack<S>: generic stack with clone-on-push semantics
Refactor Editor to use both classes. Add kill ring (kill/yank/
yank-pop), undo with coalescing, and deleteWordForward to Input.
* feat(tui): extract handleBackspace() and handleForwardDelete()
When moving up/down through lines of varying lengths, the editor now
remembers the original column position and restores it when reaching a
line long enough to accommodate it.
Example: cursor at column 10, move up to a shorter line (cursor clamps
to end), move up again to a longer line - cursor returns to column 10.
Implementation:
- Add preferredVisualCol instance property (nullable)
- Set it when moving to a shorter line during vertical navigation
- Clear it when arriving at a line that fits the preferred column
- Clear it on any horizontal movement or editing via setCursorCol()
- Detect line rewrap by checking if cursor is in middle of line
- When pressing right at end of prompt, set preferredVisualCol so
subsequent up/down navigation uses that column position
When cursor is on the first visual line and up is pressed, jump to
start of line instead of doing nothing. When cursor is on the last
visual line and down is pressed, jump to end of line instead of doing
nothing. This matches standard behavior in most native text inputs.
Add Bash/Readline-style character search:
- Ctrl+] enters forward jump mode, awaits next character, jumps to it
- Ctrl+Alt+] does the same but searches backward
- Multi-line search
- Case-sensitive matching
- Pressing the hotkey again cancels; control chars cancel and fall
through
* fix(tui): keep file suggestions open when typing in Tab-triggered mode
Previously, pressing Tab on an empty prompt or after a space would show
file suggestions, but typing a letter would dismiss them because the
text didn't look like a path pattern. Now the editor tracks whether
autocomplete was triggered via Tab (force mode) or naturally (regular
mode), and uses the appropriate suggestion method when updating.
* fix(tui): hide autocomplete when backspacing slash command to empty
Previously, typing / showed slash command suggestions, but pressing
Backspace to delete it showed file suggestions instead of hiding all
suggestions.
Instead of buffering `\` and waiting for the next key, let it be
inserted immediately. On Enter, check if preceded by `\` and treat as
newline.
Removed backslash handling from the Input component entirely.
When Tab triggers file autocomplete and there's exactly one matching
suggestion, apply it immediately without showing the menu. This makes
path completion faster by eliminating the extra Tab press to confirm.
Add insertTextAtCursorInternal() to properly handle newlines by splitting
lines at the cursor position.
- Normalize line endings (CRLF/CR to LF)
- Handle single-line and multi-line insertion
- Position cursor at end of inserted text
- Call onChange only once at the end
Refactor handlePaste() to use insertTextAtCursorInternal() for
multi-line pastes, while retaining character-by-character insertion for
single-line pastes to preserve autocomplete triggering.
Undo snapshots are captured for all edit operations:
- Word insertion, backspace, forward delete
- Word/line deletion (Ctrl+W, Ctrl+U, Ctrl+K, Alt+D)
- Yank/yank-pop, paste, autocomplete completion
- Cursor movement starts a new undo unit
- setText() pushes snapshot when content changes
Additionally, history browsing captures the undo state on first entry.
Adds deleteWordForward action bound to Alt+D, which deletes from cursor
to the end of the current word and saves to kill ring for later yanking.
Consecutive forward kills append to the same kill ring entry.
Add kill ring functionality with:
- Ctrl+W/U/K save deleted text to kill ring
- Ctrl+Y yanks (pastes) most recent deletion
- Alt+Y cycles through kill ring (after Ctrl+Y)
- Consecutive deletions accumulate into single entry
- Add Focusable interface for components that need hardware cursor positioning
- Add CURSOR_MARKER (APC escape sequence) for marking cursor position in render output
- Editor and Input components implement Focusable and emit marker when focused
- TUI extracts cursor position from rendered output and positions hardware cursor
- Track hardwareCursorRow separately from cursorRow for differential rendering
- visibleWidth() and extractAnsiCode() now handle APC sequences
- Update overlay-test.ts example to demonstrate Focusable usage
- Add documentation for Focusable interface in docs/tui.md
Closes#719, closes#525