v0.6.1
Changed
-
Resizing a document full of code is no longer dominated by re-highlighting
it. Syntax highlighting depends on the text, the language and the theme,
and a resize changes none of them — but it was being done from inside the
layout emitter, so every width change re-ran syntect over every fenced block
in the document and threw the result away.It was not a small part of the bill. A document of 120
rustfences laid
out in 199 ms, against 6 ms for the same text with the language taken off:
about 97% of a re-layout was highlighting, paid again for every step of a
drag. Six hundred fences took a full second, each time.Highlighting is now kept for as long as the parse it belongs to, which is
exactly how long it stays valid:document before after this README 8.6 ms 2.0 ms 120 rustfences198.8 ms 8.9 ms 600 rustfences999.3 ms 49.8 ms 600 fences, no language 32.4 ms 32.0 ms The last row is the control: nothing to highlight, so nothing to save.
Switching themes does pay again, once, because the theme is one of the three
things highlighting depends on — the syntax theme it names, the surface
colour forced onto every span, and the fill used where there is no language.
A one-shot render keeps nothing, since it lays the document out once and a
memo could only cost it memory; its peak stays where it was. A reader
holding a 300 KB code-heavy document pays about 10 MB for this, and about
0.1 MB for a document the size of this README.
Fixed
-
A document can no longer take the terminal down with it. Nesting deeply
enough — about 3,000 levels of> -, or 8,000 nested<div>s — overflowed
the stack while the document was being laid out: layout walks the block tree
by recursion, so the depth of the call chain was the depth of the document,
and the document chose it.That is the worst way this program can fail. A stack overflow aborts, and
an abort does not unwind, so neither the RAII terminal guard nor the panic
hook that exists for exactly this ever ran. The reader died with the
alternate screen still up, the cursor still hidden and mouse reporting still
on — a terminal that neededresetbefore it could be used again. Nor did
the document have to be your own:https://andgithub://are ordinary
sources.Nesting is now capped at 256 levels, in the markdown tree and the HTML one
alike. Past the cap a container is not represented and its children are
spliced into its parent, so the text still renders — at the capped indent
rather than a deeper one — instead of being truncated or refused. The cap is
far above anything a terminal can show: each level of quote or list costs two
cells of lead, so 80 columns is full of decoration by about level 40, and
from there the content is already pinned to the one cell the lead leaves it. -
A resize that stops no longer leaves the last frame mangled. Pane
geometry is recomputed before every draw, which is why the resize event
itself does nothing — but the recompute askedTerminal::get_framefor the
area, and ratatui only updates that insidedraw. So it was always reading
the size of the previous frame: the resize event woke the loop, the loop
laid the document out for the width the terminal used to be, and drew it
into the width it now is. Ratatui clips widgets to the buffer, so nothing
overflowed — it just came out wrong, with the contents pane still divided
where it had been and headings cut off mid-word.Dragging a window edge hid this, because each new event redrew from the
freshly-learned size. A resize that stops — the ordinary case — had
nothing following it, so the mangled frame stayed up until a key was
pressed. The terminal is now asked its size before the geometry is decided,
the same call the loop already makes after handing the screen to an editor,
and for the same reason.