Repository navigation
Conversation
…s the editor Two independent reasons the ghost silently failed to appear, both in renderGhostText. Neither produced an error; the request ran, the status indicator showed, and nothing was ever drawn. 1. pi-tui >= 1.4 wraps the cell drawn as the hardware cursor in zero-width APC markers (`ESC _ pi:fc BEL` ... `ESC _ pi:/fc BEL`) and resolves them to inverse video later, in resolveFakeCursors(). The skip logic only understood SGR runs, so it consumed a single ESC byte, fell through to the padding check and returned the lines untouched. 2. Any extension that frames the editor by patching CustomEditor.prototype.render -- pi-pretty-tui does exactly this, re-rendering at width - 2 and wrapping each row in border columns -- leaves a `|` at end of line. Requiring the rest of the row to be spaces then failed on that border. The padding match now skips SGR and APC decorations alike, captures whatever chrome follows the blank run, reserves its visible width so the ghost cannot overdraw the frame, and re-emits it byte-for-byte. A row with no usable blank run, or with a second cursor marker, still bails, so genuinely unexpected layouts are left alone. 18 tests pass, covering both cursor spellings, a styled frame border, and the unchanged-content guard.
This was referenced Oct 28, 2026
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.
The ghost silently fails to appear in two situations. Neither logs anything and neither errors — the request runs, the status indicator shows `suggesting...`, and `renderGhostText` just returns the lines untouched.
1. pi-tui >= 1.4 changed how the cursor cell is encoded
pi-tui 1.4 wraps the drawn cursor in zero-width APC markers and resolves them to inverse video later:
```js
export const CURSOR_MARKER = "\x1b_pi:c\x07";
export const FAKE_CURSOR_START = "\x1b_pi:fc\x07";
export const FAKE_CURSOR_END = "\x1b_pi:/fc\x07";
// resolveFakeCursors() later maps these to \x1b[7m / \x1b[27m
```
The cursor skip assumed an SGR sequence. On an APC marker it consumed one ESC byte, then failed the trailing-padding check and bailed.
2. A framing extension leaves a border at end of line
pi-pretty-tui patches `CustomEditor.prototype.render` — the very class this editor extends — to re-render at `width - 2` and wrap each row:
```js
const innerWidth = width - 2;
const lines = originalEditorRender.call(this, innerWidth);
if (index < bottomBorderIndex) return this.borderColor("│") + fitted + this.borderColor("│");
```
That leaves `│` after the padding, so requiring "spaces to end of line" rejected it. Reproduced by copying that patch verbatim:
```
plain layout -> ghost drawn: true
pretty-tui -> ghost drawn: false (cursor row ends with │)
```
Fix
One matcher skips SGR sequences and APC strings alike:
```js
const DECOR = String.raw`(?:\x1b[[0-9;:]m|\x1b_[^\x07]\x07)`;
```
The padding match now captures whatever chrome follows the blank run, reserves its visible width so the ghost can never overdraw the frame, and re-emits it unchanged. A row with no usable blank run, or with a second cursor marker, still bails — so the original "don't touch a layout you don't understand" guard survives for genuinely unknown content, while a border after real padding is correctly treated as chrome.
Verification
18 tests pass. New cases cover the APC spelling, a styled frame border (SGR-wrapped, as `borderColor` produces), and confirm the untouched-content guard still refuses.
Both failures are invisible at runtime, which is what made them expensive to find; the tests are the guard against a third one.