<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pardes.git/src/File.zig, branch main</title>
<subtitle>Pardes</subtitle>
<id>https://git.0x4200.cafe/pardes.git/atom?h=main</id>
<link rel='self' href='https://git.0x4200.cafe/pardes.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/'/>
<updated>2026-10-01T13:36:28Z</updated>
<entry>
<title>A +Pager keeps its program's colours: the session parses what /pager is written after its directory with ghostty-vt, SGR becomes spans drawn over the plain text, every other escape is dropped, and PagerColor off pages it plain</title>
<updated>2026-10-01T13:36:28Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T13:09:54Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=edad6d960dc0fc1165cbb3b801e0538045b2247f'/>
<id>urn:sha1:edad6d960dc0fc1165cbb3b801e0538045b2247f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>An unsaved pane restored from a dump that says nothing of its disk (no disk_hash, an older dump) asks at its first Save, as for a file changed on disk</title>
<updated>2026-10-01T13:36:27Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T13:02:59Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=9b641cbe3dc6c226be158e5051afafb9eb86c122'/>
<id>urn:sha1:9b641cbe3dc6c226be158e5051afafb9eb86c122</id>
<content type='text'>
What its text was read against is unknown, so a Save could write over
a newer file without a word; it now asks once first.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Restore reads a clean file from disk, and an unsaved one whose file changed since the Dump is said changed, its first Save asking before overwriting it</title>
<updated>2026-10-01T11:53:11Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T10:56:48Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=6c82d06cd2a15d724b8e82e1128fa15dc9e35d05'/>
<id>urn:sha1:6c82d06cd2a15d724b8e82e1128fa15dc9e35d05</id>
<content type='text'>
A Restore put back the dump's copy of every file pane and armed the
watch with the disk as it now was, so a file changed on disk after the
Dump came back as its old text, marked clean, and the next Save wrote
the old text over the new without a word.

A clean file pane's text is now not in the dump: Restore reads its file
(an older dump's copy is read past too, and used only when the file is
gone). An unsaved pane keeps its text once, base64, the plain copy beside
it dropped, with the hash of the file it was read against
(`disk_hash`); a Restore that finds another there says the file changed
on disk, and Save asks once before overwriting it, as for a change seen
while it was open. file_watch.zig's own tests were never collected (no
test root imported it): main.zig's test block does now, and the restored
watch test says what a clean restore now reads.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A +Pager pane whose text is a diff is drawn and looked at as a diff, as a diff command pane is: git diff, show and log -p page into review</title>
<updated>2026-10-01T04:35:12Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T04:14:37Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=e6ff64843b4a8986e9740c576f346690217cf5a7'/>
<id>urn:sha1:e6ff64843b4a8986e9740c576f346690217cf5a7</id>
<content type='text'>
With git paging into +Pager, a diff arrived as plain text: no colour
for its sides and a right click on a hunk line searched the word. A
+Pager pane now notes, as its text is set, whether its first 64 KiB
holds a diff header or a unified hunk, and such a pane takes the diff
highlighting and the diff look every diff pane has.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A Restore brings back clean a pane whose file was never on disk, such as Config's new init; only a file that existed when dumped is said deleted</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T00:16:32Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=f02c10bfa6d02d305ddb6d7a28b12c40035274c7'/>
<id>urn:sha1:f02c10bfa6d02d305ddb6d7a28b12c40035274c7</id>
<content type='text'>
A restored pane whose path was not on disk was marked deleted on disk,
so Config's not-yet-written init came back dirty and asked before Del,
Exit or Restore. The dump now records whether the file was on disk
(older dumps read as yes), and only one that was and is gone is said
deleted.

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>A restored pane whose file is gone from disk comes back dirty, and Del asks before throwing its text away</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T19:47:19Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=a15eabc3b9d98ef5f659ca82a2b0f2afb7451a39'/>
<id>urn:sha1:a15eabc3b9d98ef5f659ca82a2b0f2afb7451a39</id>
<content type='text'>
A dump keeps a pane's text. Restored after its file was deleted, the pane
came back clean: the watch's baseline read of the missing file failed
quietly, and Del closed it without a word. Its text was then nowhere at
all. Restore now checks the file: a local path with nothing on disk comes
back as one deleted on disk, as the watch would have said. It says so
once, logs `changed N deleted`, and is dirty, so Del, Exit and Restore
ask first.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A diff reads as the code it changes: hunks in their file's language, added and removed rows tinted</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T18:39:20Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=c04df904f2fa686cbe5ce0c078a96260af7b08bd'/>
<id>urn:sha1:c04df904f2fa686cbe5ce0c078a96260af7b08bd</id>
<content type='text'>
A .diff or .patch pane, and a command pane whose output is a diff (`git
diff`, `git show`, `diff -u`; told by a `diff --git` line, or `---`/`+++`
with a `@@` under them, in its first rows), colour each hunk's code in the
language of the file its section names (`+++ b/&lt;path&gt;`, `--- a/&lt;path&gt;` for
a deleted file), with tree-sitter, as highlightLocations does for results.

src/diff.zig walks a unified diff by its `@@` counts, so a removed line
that reads `--- x` is no header. Each side of a hunk is parsed as one text
(context and removed lines the old side, context and added lines the new),
so a string or comment across lines colours as it does in the file; a side
no line takes its colours from is not parsed. A section's hunks share a
parse, in pieces of about 40 lines (a hunk past 80 is cut), only those in
view, and each piece's colours are kept by its bytes, so scrolling back and
a terminal's every repaint parse nothing again.

Added and removed lines carry a flag in their style byte; the painter tints
their rows to the pane's edge, a little way from the page toward the
theme's ANSI green or red, and draws the prefix in that hue pushed to read
on it. A file in no known language keeps the old line colours.

A command pane is read once its command has finished: its rows are copied
once (File.DiffOutput, dropped when the pane runs again), so no frame dumps
the scrollback, and painted over what git printed. A running command is
shown as it prints.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Save makes the directories its file goes in, always: for the pane's own name and Save path alike</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T17:02:59Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=b43866d6ab784e518df8dbef374147367358ada9'/>
<id>urn:sha1:b43866d6ab784e518df8dbef374147367358ada9</id>
<content type='text'>
Whether a Save made missing directories depended on how the name had
come about. Config's pane did, a name written into a missing directory did
(since kkrqxtsp), and `Save path` and every other name did not, failing
ENOENT instead. There is now one rule: a Save makes the parent
directories of the file it writes, a pane's own or a terminal's
scrollback included, and the make_dirs flag is gone. A directory it
cannot make still fails the write with why, as fs.py's
/nonexistent-pardes-dir case shows. fs.py now also saves into missing
directories by Save path and by a written name.

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>
</feed>
