← News

Editora 0.15.0: printing, Typst structure, and menus that keep up

August 30, 2026 · 0.15.0

Editora 0.15.0 is out — 4 new features, 5 changes and 4 fixes, plus a printing path that is roughly twice as fast. Grab it from the releases page.

The theme, if there is one, is things that were wrong somewhere you could not easily look: a print path whose failure the on-screen preview clips away, a menu whose greyed-out state was decided once and never revisited, and an SVG preview that worked everywhere except in an actual installation.

A document that prints

Printing this repository’s own CLAUDE.md produced fourteen pages, most of them nearly blank and a few shrunk past legibility. It is a 382-page document.

Pagination splits on whole blocks so nothing breaks across a page edge, and a block taller than a page was given a page of its own and scaled uniformly to fit. That is right for an oversized image and catastrophic for text, because a Markdown list is one top-level block however long it is. Of that file’s 19 top-level blocks, six were over-tall — one of them a 296-page list rendered onto a single page at 0.3% scale.

An over-tall container is now regrouped into copies of itself holding as many children as fit: a long list becomes several lists, a long paragraph several paragraphs, each carrying the original’s styling so it renders identically. The text stays vector rather than being sliced into an image, so it is crisp on paper; the cost is a seam that does not hang-indent. Uniform scaling survives only for a genuinely atomic over-tall block, where it is the right answer. Same file, after: 382 pages, none scaled.

A second, older overflow surfaced alongside it. The page container’s own padding and the gaps between blocks were not being counted, so blocks summing to exactly the page height spilled over the edge — six of eight pages on a 200-item list, the worst by 31 pixels. Invisible on screen, because the preview clips.

And it is about twice as fast, which turned out to be the same investigation. Pagination was 94% layout: the search for how many blocks fit a page laid out a candidate group per step of a binary search, per piece emitted — 16.1 of 17.1 seconds on that file, laying out 1.31 million cumulative nodes. A vertical group’s height is arithmetic rather than something to measure, since it stacks its children at their preferred heights, so measuring each child once makes every prefix a sum.

CLAUDE.md      409 pages   17.1s → 9.2s     (nodes laid out 1.31M → 643K)
CHANGELOG      333 pages    3.4s → 2.4s
README          46 pages    1.6s → 1.2s

That shortcut is a property of one container, so wrapped text and side-by-side rows are still measured for real — summing them would be meaningless — and the arithmetic is treated as a hint, with every emitted page verified once against a real layout. A page that overflows is the exact bug the splitter exists to prevent, so it is not taken on trust.

Typst files get a shape

A .typ file folded at its brace pairs and nowhere else, and the Structure window listed a single entry — #align() — for a report with three sections. Typst was being routed through the generic paths, which know nothing about = Introduction.

Headings now drive both, so the outline reads as the document’s own table of contents and a section collapses like one. Folding at #align / #table brackets still works alongside it, and a long embedded listing collapses at its fence — usually the thing a reader most wants out of the way.

#let and #show bindings join the outline in document order, each nested under the section it is written in. A template file can be almost entirely bindings, and outlining headings alone left exactly those files with an empty Structure window. Three forms are deliberately left out, because each would be noise rather than navigation: #set, which configures the document rather than defining anything (a run of #set page / #set text would top most files); an indented #let inside a function body, naming something that means nothing outside it; and destructuring or #show: forms, which name nothing you could jump to.

The hard part is telling a section marker from every other use of = in a Typst file — an assignment in #let x = 1, an equality inside math, a rule of = characters — and from anything written inside a raw block, a line comment or one of Typst’s nesting block comments. Folding and the outline share one parser rather than each carrying a copy of that rule, so the two surfaces cannot disagree about where a section begins.

Every goal a Maven plugin offers

The tasks tree is built from a literal reading of pom.xml, so it could only show a goal written inside an explicit <execution>. A plugin declared for direct invocation — javafx-maven-plugin, spring-boot-maven-plugin, exec-maven-plugin — carries only <configuration>, so it contributed no row at all. javafx:run could be reached only by typing it into “Run custom…”, even though running it is the entire reason the plugin is in the pom.

Each plugin now gets a collapsed section listing the goals it actually offers, read from the plugin’s own descriptor, with each goal’s own description as its tooltip. Reading the descriptor rather than keeping a table of well-known goals means it covers whatever is in your pom instead of whatever somebody remembered.

It reads the local repository only, never the network, so opening a project never fetches anything and a plugin you have not downloaded simply contributes nothing. Results are cached, since this re-runs on every save and tab switch.

The main menu’s greyed-out items never un-greyed. The VCS menu came up almost entirely disabled inside a Git repository — Commit, Push, Pull, Fetch, Switch and New Branch, Git Log, file history and both stash entries — while the status bar an inch below showed the branch and its ahead/behind counts.

The gate was right. It was simply never re-run. Repository detection is asynchronous, so at the moment a window is built the answer is always “not in a repo”, and nothing re-evaluated it for the life of that window. That froze every context-dependent item, not only the Git ones: the preview, CSV, .http and Typst entries never followed a tab switch, and the debug step commands never followed a session suspending. The enabled state is now re-evaluated when a menu opens, and pushed from the three places the context actually moves — which is what keeps the macOS system menu bar honest, since AppKit owns the popup there and may not tell us it is opening.

Three smaller things in the same area:

Also fixed

Also

The complete list is on the What’s New page.