summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/File.zig9
-rw-r--r--src/ninep/ctl.zig14
-rw-r--r--test/snapshots/chordcut.golden1
-rw-r--r--test/snapshots/lsp-client-edit.golden3
-rw-r--r--test/snapshots/lsp-rename.golden2
-rw-r--r--test/snapshots/pipe.golden1
-rw-r--r--test/snapshots/selregex.golden1
7 files changed, 30 insertions, 1 deletions
diff --git a/src/File.zig b/src/File.zig
index b8368482..929e33bf 100644
--- a/src/File.zig
+++ b/src/File.zig
@@ -53,6 +53,10 @@ pub const State = struct {
/// Revision last known to match disk, after Save or an external reload.
/// Equal means the screen matches disk.
saved_revision: u32 = 0,
+ /// The text at `saved_revision`, hashed as the first edit after it
+ /// replaces it: an edit that brings the text back to it is clean again,
+ /// as an undo to the save point is in acme.
+ saved_hash: ?u64 = null,
watch_after_save: bool = false,
/// Seconds of the last content change, for the filesystem's stat; zero until edited.
mtime: u32 = 0,
@@ -859,9 +863,14 @@ pub fn setContent(p: *Pardes, f: *State, new: []u8) void {
if (f.mini) |*mini| mini.deinit(p.gpa);
f.mini = null;
const starts: []usize = if (f.line_starts.len > 0) editedLineStarts(p.gpa, f.line_starts, f.content, new) catch &.{} else &.{};
+ // ponytail: a whole-text hash per edit; a rolling hash when files grow large.
+ if (f.revision == f.saved_revision or f.saved_hash == null) f.saved_hash = std.hash.Wyhash.hash(0, f.content);
p.gpa.free(f.content);
f.content = new;
f.revision +%= 1;
+ if (f.saved_hash) |h| if (std.hash.Wyhash.hash(0, new) == h) {
+ f.saved_revision = f.revision;
+ };
f.mtime = pardes.ctlfs.events.now();
if (f.line_starts.len > 0) p.gpa.free(f.line_starts);
f.line_starts = starts;
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index bb562672..16935f41 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -744,6 +744,20 @@ test "a second lock is refused until the holder unlocks or closes, and binds nob
for (p.fs.opens) |o| try testing.expect(o.node == 0);
}
+test "dirty goes back to 0 when the text is the saved text again" {
+ const p = try withFile(testing.allocator, "one\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const dirty = Node.of(serial, .dirty);
+ try testing.expectEqualStrings("0\n", rd(p, dirty, 0, 8).bytes);
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .body), "two\n").reply.status);
+ try testing.expectEqualStrings("1\n", rd(p, dirty, 0, 8).bytes);
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .ctl), "Undo").reply.status);
+ try testing.expectEqualStrings("0\n", rd(p, dirty, 0, 8).bytes);
+ try testing.expectEqual(Status.ok, wr(p, Node.of(serial, .ctl), "Redo").reply.status);
+ try testing.expectEqualStrings("1\n", rd(p, dirty, 0, 8).bytes);
+}
+
test "a message from a root ctl write is the session's in the log" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();
diff --git a/test/snapshots/chordcut.golden b/test/snapshots/chordcut.golden
index d5266717..120b261f 100644
--- a/test/snapshots/chordcut.golden
+++ b/test/snapshots/chordcut.golden
@@ -77,7 +77,6 @@
|13: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #59675c,#0d1410, 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#608269, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
|14: 0-0 d,#608269, 1-1 d,#0d1410, 2-6 #616f64,#0d1410,b 7-12 #e5eee5,#0d1410, 13-59 d,#0d1410, 60-60 d,#608269, 61-61 d,#0d1410, 62-119 #e5eee5,#0d1410,
== snap ttyprobe grid=120x31 cursor=42,22
-|12: /tmp/pardes-snap/chordcut/cwd/g.txt * Save Tty Collapse D
|17: $ /tmp/pardes-snap/chordcut/cwd Tty+bash Save Mode Filter C
|18: $ ls
|20: $ stty -icanon -echo; printf '\x1b[?2004h\x1b[?1000h\x1b[?
diff --git a/test/snapshots/lsp-client-edit.golden b/test/snapshots/lsp-client-edit.golden
index c75bae4c..81079615 100644
--- a/test/snapshots/lsp-client-edit.golden
+++ b/test/snapshots/lsp-client-edit.golden
@@ -12,6 +12,7 @@
| 8 }
| 9
== snap unformatted grid=100x25 cursor=7,3
+|2: /tmp/pardes-snap/lsp-client-edit/cwd/main.rs Save Tty Collapse Del TreeContext
|3: 1 mod lib;
|4: 2
|5: 3 fn main() {
@@ -22,10 +23,12 @@
|10: 8
|11:
== snap renamed grid=100x25 cursor=12,5
+|2: /tmp/pardes-snap/lsp-client-edit/cwd/main.rs * Save Tty Collapse Del TreeContext
|3: 1 mod lib; renamed 2 range(s)
|6: 4 let x = sum(1, 2);
|7: 5 let y = sum(3, 4);
== snap unrenamed grid=100x25 cursor=12,5
+|2: /tmp/pardes-snap/lsp-client-edit/cwd/main.rs Save Tty Collapse Del TreeContext
|3: 1 mod lib;
|6: 4 let x = add(1, 2);
|7: 5 let y = add(3, 4);
diff --git a/test/snapshots/lsp-rename.golden b/test/snapshots/lsp-rename.golden
index f6dc8358..26571b26 100644
--- a/test/snapshots/lsp-rename.golden
+++ b/test/snapshots/lsp-rename.golden
@@ -18,9 +18,11 @@
| 14 }
| 15
== snap undone grid=110x25 cursor=17,10
+|2: /tmp/pardes-snap/lsp-rename/cwd/rename.zig Save Tty Collapse Del TreeContext
|3: 1 const std = @import("std");
|5: 3 fn helper(x: u32) u32 {
|10: 8 _ = helper(41);
== snap redone grid=110x25 cursor=17,10
+|2: /tmp/pardes-snap/lsp-rename/cwd/rename.zig * Save Tty Collapse Del TreeContext
|5: 3 fn renamed_helper(x: u32) u32 {
|10: 8 _ = renamed_helper(41);
diff --git a/test/snapshots/pipe.golden b/test/snapshots/pipe.golden
index 14353ebf..6b7347bf 100644
--- a/test/snapshots/pipe.golden
+++ b/test/snapshots/pipe.golden
@@ -8,4 +8,5 @@
|2: /tmp/pardes-snap/pipe/cwd/pipe.txt * Save Tty Collapse Del
|3: 1 ALPHA BETA
== snap undone grid=180x13 cursor=17,3
+|2: /tmp/pardes-snap/pipe/cwd/pipe.txt Save Tty Collapse Del
|3: 1 alpha beta
diff --git a/test/snapshots/selregex.golden b/test/snapshots/selregex.golden
index 8b45ae43..7362a85a 100644
--- a/test/snapshots/selregex.golden
+++ b/test/snapshots/selregex.golden
@@ -56,6 +56,7 @@
|4: 2 // const two = 2;
|5: 3 // const three = 3;
== snap uncommented grid=160x25 cursor=11,3
+|2: /tmp/pardes-snap/selregex/cwd/m.zig Save Tty Collapse Del TreeContext
|3: 1 const one = 1;
|4: 2 const two = 2;
|5: 3 const three = 3;