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. --- test/snapshots/filewatch.golden | 93 +++++++++++++++++++++++++++++++++++++++++ test/snapshots/filewatch.snap | 48 +++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 test/snapshots/filewatch.golden create mode 100644 test/snapshots/filewatch.snap (limited to 'test') diff --git a/test/snapshots/filewatch.golden b/test/snapshots/filewatch.golden new file mode 100644 index 00000000..64c43c85 --- /dev/null +++ b/test/snapshots/filewatch.golden @@ -0,0 +1,93 @@ +== snap edited grid=150x30 cursor=15,2 +|Kill Newcol Tutor Debug NextColor Dump Find Grep Help +| NOR /tmp/pardes-snap/filewatch/cwd/w.txt Save De NOR /tmp/pardes-snap/filewatch/cwd Del NOR /tmp/pardes-snap/filewatch/cwd Del +| 1 liMYEDITne 1 +| 2 line 2 w.txt w.txt +| 3 line 3 +| 4 line 4 +| 5 line 5 +| 6 line 6 w.txt +| 7 line 7 +| 8 line 8 +| 9 line 9 +| 10 line 10 +| 11 line 11 +| 12 line 12 +| 13 +| +| NOR /tmp/pardes-snap/filewatch/cwd Del +| +| w.txt +| +| +| +| +| +| +| +| +| +| +| +== snap reloaded grid=150x30 cursor=54,5 +|Kill Newcol Tutor Debug NextColor Dump Find Grep Help +| NOR /tmp/pardes-snap/filewatch/cwd/w.txt Save De TTY /tmp/pardes-snap/filewatch/cwd Del NOR /tmp/pardes-snap/filewatch/cwd Del +| 1 EXTERNAL $ ls +| 2 w.txt w.txt +| $ echo EXTERN''AL > w.txt +| $ +| +| +| +| +| +| +| +| +| +| +| NOR /tmp/pardes-snap/filewatch/cwd Del +| +| w.txt +| +| +| +| +| +| +| +| +| +| +| +== snap undone grid=150x30 cursor=15,2 +|Kill Newcol Tutor Debug NextColor Dump Find Grep Help +| NOR /tmp/pardes-snap/filewatch/cwd/w.txt Save De TTY /tmp/pardes-snap/filewatch/cwd Del NOR /tmp/pardes-snap/filewatch/cwd Del +| 1 liMYEDITne 1 $ ls +| 2 line 2 w.txt w.txt +| 3 line 3 $ echo EXTERN''AL > w.txt +| 4 line 4 $ +| 5 line 5 +| 6 line 6 +| 7 line 7 +| 8 line 8 +| 9 line 9 +| 10 line 10 +| 11 line 11 +| 12 line 12 +| 13 +| +| NOR /tmp/pardes-snap/filewatch/cwd Del +| +| w.txt +| +| +| +| +| +| +| +| +| +| +| diff --git a/test/snapshots/filewatch.snap b/test/snapshots/filewatch.snap new file mode 100644 index 00000000..1ac8d081 --- /dev/null +++ b/test/snapshots/filewatch.snap @@ -0,0 +1,48 @@ +# external file updates: a write from outside pardes lands in the open pane, +# and Undo brings the unsaved edit back. That is the whole contract — the +# update is committed like any other edit, so nothing has to be merged. +lines w.txt 12 +start 30 150 -n 3 +wait 8000 w.txt +stable 700 20000 +# open w.txt as a file pane: type the name into the shell, right-click it +press left 5 8 +release left 5 8 +stable 400 5000 +key i +text w.txt +key esc +settle 100 +press right 6 8 +release right 6 8 +wait 10000 line 3 +stable 700 15000 +# an UNSAVED edit on line 1 +press left 10 3 +release left 10 3 +stable 400 5000 +key i +text MYEDIT +key esc +settle 100 +stable 400 5000 +snap edited +# overwrite the file from a shell in another column. The marker is split so +# the ECHOED command line never matches the wait — only the reloaded pane does +press left 60 5 +release left 60 5 +stable 400 5000 +key c-b +stable 600 8000 +text echo EXTERN''AL > w.txt +key enter +wait 10000 EXTERNAL +stable 700 10000 +snap reloaded +# back in the file pane: one undo and the unsaved edit is there again +press left 10 3 +release left 10 3 +stable 400 5000 +key u +stable 400 5000 +snap undone -- cgit v1.3