Skip to content

fix(readline): make pasted text placeholders atomic - #674

Closed
yxlyx wants to merge 1 commit into
mainfrom
fix/issue-673-paste-spans
Closed

fix(readline): make pasted text placeholders atomic#674
yxlyx wants to merge 1 commit into
mainfrom
fix/issue-673-paste-spans

Conversation

@yxlyx

@yxlyx yxlyx commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Closes #673.

What changed

  • Added a semantic paste store that owns each collapsed paste body and tracks the byte range of its visible [Pasted text #N +L lines] label.
  • Rendered only live, position-validated paste spans with the existing reverse-video/emerald attachment treatment.
  • Made ordinary and word navigation skip paste spans as one unit; Backspace, forward delete, Ctrl/Option word deletion, line deletion, completion, insertions, and clears now update or detach span identity.
  • Expanded only tracked spans on submit and consumed their identity after expansion, so a typed lookalike remains literal and repeated expansion cannot duplicate a body.
  • Detached paste identity when history replaces the draft, because history persists display text but not hidden paste bodies.
  • Split history replay into readline_replay.zig so readline.zig remains below the 600-line source ceiling.

Why

Problem / failure mode

The composer stored long paste bodies out of band but represented them with ordinary editable text. Submission searched for the exact display string and replaced every match. Users therefore had no visual proof that a marker still had an intact payload, Option/Alt+Backspace deleted the marker word by word, and deleting then manually recreating an identical label could resurrect hidden content.

Reason for this approach

Attachment identity must not be inferred from presentation text. Positional semantic spans let the editor distinguish a live paste from an identical typed string, render that distinction, shift the attachment with surrounding edits, and detach it whenever an edit touches the span. The same ranges also define atomic cursor and deletion boundaries.

Constraints and trade-offs

  • Short single-line paste behavior remains ordinary inline text.
  • Full multiline bodies remain out of the visible composer and preserve their exact submitted bytes.
  • History replay deliberately drops semantic identity: the history layer has no hidden paste body to restore, so highlighting or expansion there would be misleading.
  • This change is limited to the raw terminal readline/TUI path; GUI behavior is unchanged.

Rejected alternatives

Adding paste labels to the existing string-based marks list would highlight every identical lookalike and preserve the resurrection bug. Special-casing word-boundary deletion without semantic identity would improve Option+Backspace but would not establish whether a payload was still attached or make submission safe.

Verification

  • scripts/eval-tier1.sh
    • formatting and 600-line ceiling green
    • spec and test reachability green
    • build green
    • 1,760 unit tests passed, 1 skipped
    • 459/459 fullscreen-TUI tests passed
    • all 17 PTY probes passed
    • invariants and SDK synchronization green
  • zig test src/readline_paste.zig — 8/8 focused state-machine tests passed.
  • zig build test -Dtest-filter='paste' --summary all — 60/60 relevant tests passed.
  • Independent real-PTY verification confirmed:
    • paste and file attachment spans use the same ANSI chip styling,
    • ESC DEL (Option/Alt+Backspace) removes the complete paste marker,
    • manually retyping the removed label submits it literally without the hidden body.
  • Independent edge-case passes covered multiple spans, deletion/offset shifts, lookalike labels, history replay, monotonic IDs, and an adversarial body beginning with its own display label expanded twice without duplication.

Track collapsed paste labels as positional semantic spans instead of
re-associating hidden bodies through display-string matches. Live spans now
render with attachment highlighting, move as one cursor/word unit, detach on
edits, and are consumed on expansion so typed lookalikes cannot resurrect or
duplicate removed content.

Split history replay into a focused sibling module so replayed draft labels
remain ordinary text and readline stays within the source line ceiling.

Closes #673

Co-Authored-By: Codegraff <blackfloofie@codegraff.com>

@justrach justrach left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked against #673 acceptance on the current main composer (string-match expand) vs this branch.

This is the right fix: identity lives on a positional paste store, highlight is only for live validated spans, Option/Alt+Backspace and word-nav treat the marker as one unit, submit expands only tracked spans, and a typed lookalike stays literal. History dropping semantic identity is also correct — there is no hidden body to restore.

CI is green (zig/sdk/windows). No follow-up needed from this review; leaving #673 to close with the merge.

@justrach

Copy link
Copy Markdown
Owner

Folded into release/v0.0.282 (#696). Closing as superseded.

@justrach justrach closed this Aug 31, 2026
@cursor
cursor Bot deleted the fix/issue-673-paste-spans branch August 31, 2026 01:30
yermakoffivan pushed a commit to yermakoffivan/codegraff that referenced this pull request Aug 31, 2026
…ders

yxlyx: semantic paste spans so [Pasted text #N] is one navigation/delete
unit and a typed lookalike does not resurrect a hidden body.
yermakoffivan pushed a commit to yermakoffivan/codegraff that referenced this pull request Aug 31, 2026
…justrach#694

Record the three product merges on the new release branch, remap the
TLS-generation ADR to 0048 so 0042 stays TUI claims, and leave justrach#277 /
justrach#200 parked.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI: render pasted-text placeholders as highlighted atomic spans

2 participants