Skip to content

fix(dom): make size() match the grid it builds - #189

Open
lix42 wants to merge 1 commit into
ratatui:mainfrom
lix42:fix/dom-size-matches-grid
Open

lix42 wants to merge 1 commit into
ratatui:mainfrom
lix42:fix/dom-size-matches-grid

Conversation

@lix42

@lix42 lix42 commented Oct 10, 2026

Copy link
Copy Markdown

Fixes #188.

size() returned get_size(), a window (on mobile, screen) size divided by a fixed 10×20 cell, while the grid is the parent divided by the measured cell. When the frame was larger than the grid, draw indexed past the last cell and panicked (on phones, or with any cell larger than 10×20 on desktop).

Change

  • The resize listener measures the cell and the grid size right away and stores them. size() returns that pending size, or the current grid's size, and the next draw rebuilds the grid at it.
  • Measuring had to move out of draw: ratatui calls size() (autoresize) before draw, so a size() that read the grid would always be one resize behind.
  • initialized is now a plain bool, since only draw touches it.

Behavior changes

  • The frame is now the whole grid. The old - 1 margin is gone.
  • The old grid is removed in the resize handler rather than in the next draw. With draw_web, which draws in requestAnimationFrame, the browser runs resize handlers before animation frame callbacks in the same rendering update, so the empty parent isn't painted. An app drawing from some other timer could show one blank frame after a resize.

Tests

Two wasm_bindgen_tests in dom.rs check that terminal.size() equals the rows × columns of the grid in the DOM, after the first draw and after a resize. Both panic on main and pass here. wasm-pack test --firefox --headless, cargo test --all-features --all-targets, cargo fmt --check and cargo doc pass; clippy reports no new warnings.

Not in this PR

  • get_size() is unchanged; the canvas backend still uses it.
  • The resize handler clears the parent with set_inner_html(""), as draw did before, which also removes anything else in the parent. Removing only the grid would be narrower.
  • Resize events aren't debounced. Debouncing the whole measurement would save rebuilds while a window is being dragged, without the frame and the grid ever disagreeing.

Possibly related: #186. #167 (draft) also changes how size() is computed.

size() returned get_size(): the window (the screen, on mobile) divided by
a fixed 10x20 cell. The grid is the parent divided by the measured cell.
When the frame came out larger than the grid, draw indexed past the last
cell and panicked.

Measure in the resize listener instead of in draw, so size() reports the
new grid size before ratatui draws, and rebuild the grid at that size in
the next draw.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

This branch has not been deployed

No deployments
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.

DomBackend panics (index out of bounds) when size() is larger than the grid it builds

1 participant