Repository navigation
feat(html): lay out only the lines of a text file near the viewport - #1247
Merged
Merged
Conversation
A text file of one million lines took 151 s to load in Chrome, and its renderer held 6.3 GB. Now it takes 0.85 s and 0.9 GB. - The view writes the lines in chunks of 256. A chunk has `content-visibility: hidden` unless `text.js` marks it near the viewport, so the browser lays out a few chunks at a time. With `auto` instead, Chrome lays out every chunk once on the first frame. That costs 7.5 s for the same file. - A line number is a CSS counter in the line itself. So the gutter needs no `ResizeObserver`, which doubled the load, and a wrapped line keeps its number beside it. The containment of a chunk hides a counter on the chunk, so its first line states where it counts from. - `odr.search` shows the chunk of a hit before it scrolls to it. - Without the script, the chunks fall back to `auto`. The find of the browser does not reach a chunk far from the viewport. `odr.search` does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017QtawyvLP2SCnoBtnVfFed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017QtawyvLP2SCnoBtnVfFed
The view states the digits of the largest line number once. An edit that went from 9 to 10 lines put the number 10 into a gutter of one digit. `renumber` now states the digits again, as it states the start of each chunk. Also state the reason for the start in each chunk in the same words as the design: style containment keeps the counter inside the chunk. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHNzLmVv1mFWfPitHASucN
andiwand
force-pushed
the
feat/text-chunks
branch
from
October 24, 2026 18:33
dbd34f8 to
c5b06c3
Compare
andiwand
added a commit
that referenced
this pull request
Oct 24, 2026
The status said that nothing of the design has landed, but #1247 and #1248 did. Also say how `spreadsheet.js` learns that a chunk became near: `viewport.js` dispatches an event on it. A change of the class alone tells no script. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHNzLmVv1mFWfPitHASucN
andiwand
added a commit
that referenced
this pull request
Oct 24, 2026
* docs: design the chunks of a sheet for lazy loading `content-visibility` has no effect on a table row, so a chunk of a sheet is a table of its own (decision 6): - A `div.odr-sheet` takes the attributes of the sheet. - The ruler gets a sticky table of its own. - Every column gets a fixed width. A column that states none gets the width of its longest text. - A chunk ends only where no merge is open. - Each chunk states the estimated height of its rows. - The first chunk stays near where shapes hang from A1. For each script that reads the rows or the geometry, the design states how it works with chunks. Level 2 of a text file drops out of the order of work, because it gained little when measured. * docs: state that level 1 of lazy loading has landed for text and pdf The status said that nothing of the design has landed, but #1247 and #1248 did. Also say how `spreadsheet.js` learns that a chunk became near: `viewport.js` dispatches an event on it. A change of the class alone tells no script. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
andiwand
added a commit
that referenced
this pull request
Oct 24, 2026
The views lay out only the parts near the viewport since #1247, #1248 and #1250, and this PR adds `HtmlConfig::lazy_layout`. A consumer notices both, but the changelog had no entry. Also check the round trip of the jni test with `assertFalse`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHNzLmVv1mFWfPitHASucN
andiwand
added a commit
that referenced
this pull request
Oct 24, 2026
* feat(html): add a switch for lazy layout `HtmlConfig::lazy_layout` is on by default. Off, no view writes a chunk or the style that hides one, so the browser lays out everything. Its own find and a screen reader then reach every line, row and page. A host can take that where a file is small. - The text and sheet views write all their lines or rows as one block. The pdf pages get no chunk class. - `chunk_classes` gives the classes of a chunk, empty where the switch is off, and `write_chunk_style` writes nothing then. - The text styles move from `.odr-chunk` to `.odr-text-lines`, so a text page without chunks keeps its line numbers. - The apple, jni and python bindings carry the switch. * test: advance the reference output to the lazy layout switch The design names the switch, and the pins move to the reference output of the renamed text class and the reordered pdf page classes. * docs: add the lazy layout and its switch to the changelog The views lay out only the parts near the viewport since #1247, #1248 and #1250, and this PR adds `HtmlConfig::lazy_layout`. A consumer notices both, but the changelog had no entry. Also check the round trip of the jni test with `assertFalse`. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
🤖 Generated with Claude Code
Refs #764.
Summary
This is level 1 of
docs/design/lazy-loading.md, for text files. With a text file of 1 M lines (71 MB) in headless Chrome:content-visibility: hiddenuntiltext.jsmarks it near the viewport with anIntersectionObserver(one screen of margin). So the browser lays out a few chunks at a time.content-visibility: autoalone takes 13.5 s here, because Chrome lays out everyautochunk once on the first frame. Without the script, the chunks fall back toauto(<noscript>), andbeforeprintshows every chunk.::before, with empty alternative text for screen readers). So the gutter column and itsResizeObserverare gone. That observer measured every line and doubled the load. A wrapped line keeps its number beside it. A chunk has style containment, so the counter does not count on past it, and the first line of each chunk sets where it starts. After an edit that adds or removes lines, the editor sets the starts and the digits of the gutter again, and it removes a chunk that has no line left.odr.searchshows the chunk of a hit before it scrolls to it, as it opens a folded<details>. The find of the browser does not reach a far chunk. The design doc listshidden="until-found"as an open question.odr-chunk,odr-chunk-near), so pdf and sheets can use them later.The reference output changes for the five
txtpages andtext.css,text.jsandsearch.js. The output repomainis at b0a3b91, and the pin is advanced. The gutter is now as wide as the digits of the last line, so the text moves by about a pixel.Test
html.a_text_file_writes_its_lines_in_chunks: a 300-line file. The test checks the number of digits, where each chunk counts from, and the short last chunk. All 2,529 tests pass.test/browser/plaintext: 54 checks, 0 failed. The fixture now has two chunks, so the checks cover an Enter, a join and a delete across the chunk boundary.Review fixes
renumbernow sets--odr-text-digitsagain. Two new checks intest/browser/plaintextcover it.text.js, so the rendered pages do not change. CI compares onlyoutput/, so the reference output stays at b0a3b91.