From eefac04995ffad847a4098f16d2e82ccab16438b Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Fri, 31 Jul 2026 04:15:41 -0300 Subject: open files follow the disk, and undo is the merge strategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An external update is pushed onto the undo stack exactly like an edit the user typed, so unsaved work is one `u` away and pardes never has to merge anything. That is the design, not an implementation detail: the whole feature is pushUndo() then setContent(). One inotify instance in the tty shell, blocking in readVec through std.Io on a concurrent task started beside the pty readers — after loop.start(), so the forkpty ordering is untouched. It watches the containing DIRECTORY, because an editor rewrites by rename-over and a watch on the file would follow the dead inode, and it listens for CLOSE_WRITE rather than MODIFY, which is one event per finished writer and most of the debounce for free. Our own Save does not reach the undo stack: each watch keeps a hash of the bytes last seen on disk and save_file restamps it. A hash rather than mtime and size because the reload has to read the file anyway. The core stays sans-IO — one watch effect out, one file_changed event in, and a shell that cannot watch simply never sends the event, which is what the gui and the web platform do. Linux only; fanotify is what the build system uses and is rejected in a comment: it exists for thousands of directories across mounts, and sixteen panes of inotify is a third of the code with no kernel floor. New golden filewatch: edit without saving, overwrite from a shell in another column, watch it reload, undo, get the unsaved edit back. None moved. --- src/gui/gui.zig | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/gui.zig b/src/gui/gui.zig index d8086981..998573b5 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -2137,6 +2137,11 @@ fn drainEffects( _ = c.SDL_SetClipboardText(z.ptr); }, .lsp => |e| if (threads_ok) spawnLsp(core, gpa, queue, e), + // ponytail: the SDL shell does not watch files. Everything the core + // needs is already here (the effect and the file_changed event) — what + // is missing is the ~50 lines of inotify plumbing in tty.zig, and a + // shell that never delivers the event simply never reloads. + .watch => {}, .quit => {}, }; } @@ -2174,8 +2179,9 @@ fn drainEffectsWeb(core: *pardes.Pardes, gpa: std.mem.Allocator, g: *Gui) void { }, // look on a URL → a new tab .open_link => |url| openLinkWeb(gpa, url.slice()), - // nothing to spawn/write/resize/save/dump into — all no-ops - .spawn, .write, .resize_pty, .save_file, .write_dump, .lsp, .quit => {}, + // nothing to spawn/write/resize/save/dump into, and no filesystem to + // watch — all no-ops + .spawn, .write, .resize_pty, .save_file, .write_dump, .lsp, .watch, .quit => {}, }; } -- cgit v1.3