<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pardes.git/test/perf.zig, branch release-0.24</title>
<subtitle>Pardes</subtitle>
<id>https://git.0x4200.cafe/pardes.git/atom?h=release-0.24</id>
<link rel='self' href='https://git.0x4200.cafe/pardes.git/atom?h=release-0.24'/>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/'/>
<updated>2026-10-01T22:57:27Z</updated>
<entry>
<title>Zerox opens a second pane on a file pane's buffer: one text, undo and unsaved state, a scroll and a cursor each; an edit in either is spliced into both at File.setContentSpan, O(the edit) more, and what a Save, a get, the disk watch or a rename changes on one is copied to the rest after each step</title>
<updated>2026-10-01T22:57:27Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T22:50:32Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=dce94f4453735a6f71385cc020ee79c7604609e7'/>
<id>urn:sha1:dce94f4453735a6f71385cc020ee79c7604609e7</id>
<content type='text'>
Twins share the content buffer, the History and, while it is one, the line
index; the other twin's cursor and scroll move past the splice as acme
moves a clone's q0. Del of one twin asks nothing while another holds the
text, Exit lists the text once, and a closed twin keeps a copy of its own
until it is torn down. Both are in the index, each its serial, one name.
An event reader on one hears no edit made through another (first cut).
A dump keeps the twins as two panes on the file, not linked again.
perf: edit-twin, typing beside a twin of the 50k-line file, gated within
3x of edit-char in the same run; the three baselines re-recorded for it.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A selection deep in a long line costs a render what one at its start does: 5 MB in, /screen goes from 14.7 s to 5 ms</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T21:40:41Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=9a256d34ebca317e3007adf71c2b94016059d4a3'/>
<id>urn:sha1:9a256d34ebca317e3007adf71c2b94016059d4a3</id>
<content type='text'>
Every render measured a selection's and the cursor's columns from the
start of their line (lineDisplayOffset walked the whole prefix twice),
so a selection near the end of a 5 MB line stalled each frame, 3 s at
1 MB in and 14.7 s at 5 MB. The cost grew with the offset, with Wrap on
or off. Three changes make it independent of where the selection is:
- display width adds (a tab is tab_width wherever it stands), so the
  offset between two columns is the width of the text between them,
  never the prefix;
- the selection's rows are clamped to what is shown: a row wholly
  before the selection is skipped, a start before the row's first
  column starts there, and an end past its last column ends there;
- a head or cursor whose column lies past its visible row (the last
  visible row of a line owns every column after its start) is not
  measured, since it is not drawn.
Measured on a Debug build, 5 MB line: offset 10, 1 MB and 5 MB now take
11, 6 and 5 ms per /screen. A new perf gate case, deep-sel, renders with
the selection 2 MB into a line: 83 us on Debug. The baselines were
re-recorded for the new harness.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>An append to a body through 9P costs its own bytes, not five passes over the whole body: 60 KB appends go from 35.7 to 2.1 ms each</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T13:50:18Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=048e81e3471c73b9ac690901819976f689f6a4ce'/>
<id>urn:sha1:048e81e3471c73b9ac690901819976f689f6a4ce</id>
<content type='text'>
Round 25 measured bulk body writes at about 8 ms a write. There is no frame wait in it: a profile of open, write, clunk in a loop found the flush of each close walking the whole body five times. dotOf, setDot and showOffset turned the cursor between offsets and rows by counting every newline from the top; setContent found the line index's changed span by comparing old and new byte for byte, and hashed the new text to see whether it was back to the saved one. The rows now come from the file's line index by binary search (checked against the counting at every offset), a splice tells setContent the span it changed, and the text is hashed only when its length is the saved text's. Measured over 9P on a Debug build: 60 KB appends 35.7 to 2.1 ms, 8 KB 5.3 to 0.8 ms, 1 KB 1.3 to 0.9 ms. What is left is two copies of the text an edit (the splice's and the undo snapshot's). The perf gate gains body-appends, 64 appends of 8 KB on the 50k-line file, and its three baselines are recorded again.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Terminal.zig is terminal.zig: a file of functions and no fields takes a namespace's lowercase name</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T23:56:14Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=04b047fb366ea2c595708fb62467f690fce4b9ec'/>
<id>urn:sha1:04b047fb366ea2c595708fb62467f690fce4b9ec</id>
<content type='text'>
The last of the deferred renames, now that the tty and theme agents have landed: panes.terminal at its importers, the alias lines in Text.zig and File.zig and panes.zig's own uses following. dump.zig's Terminal struct, a dump record, is not this. The served sources list and docs/design.typ name the new file. test/perf.zig's references change, so the three perf baselines take its new harness id with their numbers as recorded. No behaviour changes.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Mini.zig is mini.zig: a file of functions and no fields takes a namespace's lowercase name</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T23:25:28Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=2b388888348860097967ae04d03f68c00a70472c'/>
<id>urn:sha1:2b388888348860097967ae04d03f68c00a70472c</id>
<content type='text'>
The naming the split agreed on, deferred until now; panes.mini is its name at its importers. File.zig keeps its alias line (const Mini = panes.mini) so the file another agent is working in changes by that line alone. The served sources list and docs/design.typ name the new file. No behaviour changes; test/perf.zig's two references change, and since the perf harness is keyed by its own text, its three baselines are recorded again (under other agents' builds, so a little slower).

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>An open's writes in a row to one place go in as one edit: a 10 MB body write is linear</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T19:17:26Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=eb47ded95f43e50dc24b841289b68814105dcfb7'/>
<id>urn:sha1:eb47ded95f43e50dc24b841289b68814105dcfb7</id>
<content type='text'>
Each body or data write copied and hashed the whole buffer, so a write the mount cut in 8 KB pieces was quadratic: 10 MB took 50 s and a 1 MB insert into 10 MB 11 s, holding the editor's turn. An open's appends to body, or inserts going on at data's address, are now held and put in as one splice (one copy, one undo step, one line-starts pass) before any other request, the close, or the editor's step once the writes pause 20 ms. fs.py-driven: 2 MB 2.19 -&gt; 0.16 s, 10 MB 50.17 -&gt; 0.78 s, 1 MB data into 10 MB 11.49 -&gt; 0.26 s. A body-2m case (2 MB in 256 KB writes on one open) joins the perf gate: 84023 -&gt; 15785 us; baselines re-recorded.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>The theme's chrome is worked out once, not per grapheme; still post passes let the GUI rest; a perf gate</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T16:19:08Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=4e224b7c7e67fafcbe7359fcf534048e254b701d'/>
<id>urn:sha1:4e224b7c7e67fafcbe7359fcf534048e254b701d</id>
<content type='text'>
somtrmsz's contrast floors made ChromeTheme.fromTheme run its focus-tint
and separator searches (pow calls each), and Output's RowDecoration.styleAt
called it for every grapheme of every highlighted row: the 50k-line file's
render went from 0.11 ms to 13 ms. Pardes.bodyChrome now keeps the theme's
chrome, worked out again only when the theme differs; recolorSyntax asks
for it once a decorated row, and a plain row (nearly every row of a file)
never asks. ReleaseFast, medium fixture, median us, before -&gt; after (main):
render 13150 -&gt; 76 (111), key-down 14658 -&gt; 79 (110), wheel 13589 -&gt; 76
(109), open 14891 -&gt; 2095 (2055), edit-char 16703 -&gt; 3006 (1251; the rest of
that gap is editing and tree-sitter, not this).

Post.animating asked for frames whenever the window had focus and any pass
was ready, so a still pass kept the GUI drawing at the display's rate
(Bloom: 49% of a core idle, in a hidden test window). A pass now says
whether it moves on its own: the CRT (its hum and dither) and a Shadertoy
file whose source reads iTime, iFrame or iDate (shader_build.readsTime; the
flag rides the wire's post message); Bloom, Vignette and Grain are still.
Bloom idle: 49% -&gt; 1.2%, as with no pass.

zig build perf-gate: the 50k-line file's gestures, each's fastest sample
within 3x of the recorded baseline's (test/perf-baseline-&lt;platform&gt;-
&lt;optimize&gt;.json, recorded from this build), run with every unit-test. On
the regressed code it fails at 180x for render.
</content>
</entry>
<entry>
<title>Give a pane's body its own Text holding the cursor, selections, mode and undo</title>
<updated>2026-10-01T03:12:14Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T02:06:11Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=95a3a1bb822e583988bfe0f312d0ef219b27a454'/>
<id>urn:sha1:95a3a1bb822e583988bfe0f312d0ef219b27a454</id>
<content type='text'>
acme keeps what edits a text in its Text (dat.h:171-190) and the window
holds a body and a tag of that type. The cursor, the selections, the modal
state and the edit-buffer undo move off Pane into Text.zig, Pane holds
them as its body, and the edit and normal-mode operations take the Text
they edit. Nothing changes in behaviour; this is the step that lets the
tag become a second Text.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Move looking out of pardes.zig into look.zig</title>
<updated>2026-10-01T03:12:14Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T01:27:42Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=82551f77833a09b313bd3e58371582abd1aedcc4'/>
<id>urn:sha1:82551f77833a09b313bd3e58371582abd1aedcc4</id>
<content type='text'>
Pure move, no behaviour change (acme keeps this in look.c): expanding the
word under a click (ExpandedWord, expandedWord, expandedSel, cursorWordSel),
the n/N walk (LookFrom, lookEdge, lookStand, lookWalkPanes, lookPast,
wholeRowSpan, lookSpanIn, lookWalk, landLookSpot, noteLookSource,
armLookWalk), search results (Search, SearchStart, submitSearch,
lookFirstHit, runSearch, searchStep, jumpResult), the look-hover preview
(LookHoverWait, LookHoverPreview, FileWordSpan, PdfWordPreview,
invalidateLookHover, cancelLookHover, lookHoverPane, noteLookHover,
refreshLookHoverFromRaw, advanceLookHover) and lookAt with its targets
(focusPaneLine, selectSpan, openPaneTarget, focusPaneByPath,
clearNavigationSelection, resolveLookTarget, locationText,
canonicalLookLocation, pdfLinkLocation, followPdfLink), with five tests, go
verbatim to the end of look.zig after its word and target resolution.

The methods become free functions taking `p: *Pardes`; their 143 call sites
change from `p.lookAt(..)` to `look.lookAt(p, ..)` (tests reach them as
`pardes.look.x`). Inside look.zig the moved code's `look.` prefix drops.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Move text editing out of pardes.zig into edit.zig</title>
<updated>2026-10-01T03:12:14Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T01:09:27Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=ff953a6236ebdf97c73deda86fd9005906a2071b'/>
<id>urn:sha1:ff953a6236ebdf97c73deda86fd9005906a2071b</id>
<content type='text'>
Pure move, no behaviour change (acme keeps this in text.c): which text a
pane edits and how it maps to the screen (editText, editTextEol,
setEditText, paneCursorLines, paneByteAtDisplay, pinPaneCursor,
flatSurface, paneWrapWidth), insert mode (enterInsert, handleInsert,
insertKey, insertTab, exitInsert, clampFileCursor), the d/c/y/p edit
operations with replace, case, join, indent, comment, number, textobjects
and surround, undo and redo, yank/clipboard/paste (setYank, setClipboard,
ClipRequest, clipRequest, typeToTty, applyPaste, clipYank), and the pointer
selections as text (PointerTextSelection, pointerTextSelection,
capturePointerSelection, paneText, pointerSourceLine, selectionText,
spanHas, currentSelText), with four tests, go verbatim to edit.zig.

The methods become free functions taking `p: *Pardes`; calls change from
`p.insertKey(..)` to `edit.insertKey(p, ..)` (pardes.zig, body_layer.zig,
selection_pipe.zig, builtins.zig, test/hxdiff.zig, test/perf.zig). In
executeNormalAction the `.edit =&gt; |edit|` capture becomes `|op|`, since it
would now shadow the edit import. test/lspbench.zig's first anchor follows
its needle into src/edit.zig.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
