* fix(tui): blockquote multiline rendering and wrapping
Fix two bugs in blockquote rendering:
1. ANSI codes split incorrectly on newlines - when text tokens contain
newlines, applyDefaultStyle() wrapped the entire string including the
newline in ANSI codes. Any caller splitting by \n would break the codes.
Fixed by splitting text by newlines before styling in renderInlineTokens().
2. Wrapped blockquote lines lost the │ border - long blockquote lines
that wrapped to multiple lines only had the border on the first line.
Fixed by wrapping within the blockquote case and adding border to each line.
* test(tui): add test for inline formatting inside blockquotes
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 isImageLine() to terminal-image.ts with single startsWith check based on detected terminal protocol
- Replace dual includes() checks in tui.ts with imported isImageLine()
- Add image line handling to markdown.ts to skip wrapping and margins for image escapes
- Consolidate Box cache into RenderCache type with childLines/width/bgSample/lines fields
- Use in-place mutation in applyLineResets() to avoid array allocation
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.
- Add alt+b/alt+f as alternative bindings for cursorWordLeft/cursorWordRight
- Add ctrl+d as alternative binding for deleteCharForward
- Fix ctrl+d in custom editor to perform delete when text is present
(previously it was always consumed, even with non-empty input)
Closes#1043
Co-authored-by: Jason Ish <ish@unx.ca>
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.
Appended lines were not committed to terminal scrollback because the
renderer used cursor movement (CSI B) and carriage return without
linefeed. This caused earlier content to be overwritten when the
viewport filled up.
Changes:
- For appended lines, emit \r\n to create real scrollback lines
- When target row is below viewport, scroll with \r\n before positioning
- Add PI_TUI_WRITE_LOG env var for debugging raw ANSI output
- Add fullRedraws readonly property to TUI class
- Add viewport-overwrite-repro.ts test script
fixes#954
I lost my ability to select up and down in the session selector because
of some hardcoded keybindings again... So, I am adding these
configurable keybindings so I can `ctrl+p` to select up :-)
### Changes
Adds 4 new keybinding actions for the session picker (/resume):
- `toggleSessionPath` (ctrl+p) - toggle path display
- `toggleSessionSort` (ctrl+r) - toggle sort mode
- `deleteSession` (ctrl+d) - delete selected session
- `deleteSessionNoninvasive` (ctrl+backspace) - delete when query empty
Refactors session-selector to use `kb.matches()` instead of hardcoded key checks.
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.
setCustomEditorComponent() was not copying the paddingX setting from
the default editor to extension-provided editors. Also propagate live
changes from the settings callback.
- allocateImageId() now returns random IDs instead of sequential
- Static images no longer auto-allocate IDs (transient display)
- Only explicit imageId usage (like DOSBox) gets tracked IDs
- Suppress emulators exit logging in DOSBox dispose
Fixes image replacement bug when extension and main app both
allocated sequential IDs starting at 1.
- Add allocateImageId() to generate unique image IDs
- Add deleteKittyImage() and deleteAllKittyImages() functions
- Image component now tracks its ID and has dispose() method
- renderImage() returns imageId for tracking
- DOSBox: reuse single image ID for all frames, delete on dispose
Fixes image accumulation hitting terminal quota and lingering
images after component close.
Autolinked emails like user@example.com were rendered as
'user@example.com (mailto:user@example.com)' because the comparison
token.text === token.href failed (text lacks mailto: prefix).
Now strips mailto: prefix before comparing, so autolinked emails
display without redundant URL in parentheses.
- Add maxLinesRendered to track terminal's working area (grows with content, only resets on full clear)
- Fix viewport calculation: use maxLinesRendered instead of cursorRow for correct viewport bounds
- Separate cursorRow (end of content for viewport calc) from hardwareCursorRow (actual cursor position)
- Refactor full render into fullRender(clear) helper to reduce duplication
- Fix shrink-clearing: properly clear extra lines when content shrinks
- Add PI_TUI_DEBUG=1 env var for render debugging (writes to /tmp/tui/)
The core issue was that after partial renders (e.g., overlay show/hide), the viewport
calculation used cursorRow which reflected where rendering stopped, not where content
ended. This caused incorrect viewport bounds, leading to cursor movement into scrollback
(unreachable) or rendering at wrong positions.
Additionally, when content shrank (e.g., selector dismissed), the terminal still had
the old lines as blank space. maxLinesRendered tracks this so viewport calculations
account for the terminal's actual working area.