Skip to content

getViewport() returns corrupted data when viewport spans multiple pages #139

@darrinm

Description

@darrinm

Description

renderStateGetViewport in the WASM build resolves the viewport top-left position independently for each row using pages.pin(.active). When the viewport spans multiple internal pages, this per-row resolution can produce inconsistent results, leading to corrupted viewport data.

Additionally, scrollbackLimit is passed as a line count but Terminal.init() interprets max_scrollback as bytes, causing the scrollback buffer to be much smaller than intended and making the page-spanning condition occur more frequently.

Symptoms

  • getScrollbackLength() drops unexpectedly (e.g., 498 → 269) after repeated writes
  • getViewport() returns rows with content from different terminal lines merged together
  • Both getViewport() and getLine() return the same wrong data
  • Corruption frequency depends on column width:
    • cols=80: OK
    • cols=120: CORRUPT
    • cols=130: CORRUPT
    • cols=140: OK
    • cols=160: scrollback drops but viewport may appear OK (merge lands on empty rows)

Root cause

The native Ghostty renderer reads cell data from cached row pins in RenderState.row_data (built during update()), which guarantees consistent page resolution across all viewport rows. The WASM renderStateGetViewport instead calls pages.pin(.active) per-row, which can resolve to different pages inconsistently when the viewport straddles a page boundary.

Reproduction

  1. Create a terminal at cols=130, rows=39, scrollback=10000
  2. Repeatedly write ~68 lines of escape-heavy output (SGR 256-color, truecolor, attributes)
  3. After ~8 repetitions, call getScrollbackLength() and getViewport()
  4. Scrollback length will drop and/or viewport rows will contain merged content

Expected behavior

getViewport() should return consistent, correct row data regardless of internal page layout. scrollbackLimit should be interpreted consistently between the JS config and WASM init.

Fix

Draft PR with fix and regression tests: #133

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions