summaryrefslogtreecommitdiff
path: root/src/ninep/events.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 07:05:46 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit1b513045336b3c7381c447ffa8c9167f8b1a5a0a (patch)
treebf9377e7178f367c3ad0b35446f4aa9eaf9600d2 /src/ninep/events.zig
parent96383331f09e8af3fa24f767b3c56863309723b8 (diff)
downloadpardes-1b513045336b3c7381c447ffa8c9167f8b1a5a0a.tar.gz
pardes-1b513045336b3c7381c447ffa8c9167f8b1a5a0a.zip
A builtin's Verbose announcement is logged only when it succeeds
A failure said while it ran (Exit's refusal, a Del refused) or later by the host (a Save's write, a Dump's) left `msg N Save` in the log as if it had worked. The announcement's record is remembered and taken back out on either, unless a follower read it already. A refused pane/new logs its err alone, and a failed Dump says its reason in words (`file not found`, not `FileNotFound`) so its msg goes and the err is the one record. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/events.zig')
-rw-r--r--src/ninep/events.zig38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/ninep/events.zig b/src/ninep/events.zig
index 2b7c1c1d..44ad560e 100644
--- a/src/ninep/events.zig
+++ b/src/ninep/events.zig
@@ -232,6 +232,44 @@ pub fn dropAnnouncement(p: *Pardes, serial: u32, text: []const u8) void {
p.fs.log.buf.shrinkRetainingCapacity(last.at);
}
+/// The sequence number of the newest log record when it is a msg that
+/// ends in `word` alone: not one counted (`(x2)`) over an earlier say.
+pub fn newestSaying(p: *Pardes, word: []const u8) ?u64 {
+ const last = newest(p) orelse return null;
+ if (!std.mem.startsWith(u8, last.text, "msg ") or !std.mem.endsWith(u8, last.text, word)) return null;
+ if (last.text[last.text.len - word.len - 1] != ' ') return null;
+ return last.seq;
+}
+
+/// Takes record `seq` back out of the log, unless a follower has read it.
+pub fn dropRecord(p: *Pardes, seq: u64) void {
+ if (followerRead(p, seq)) return;
+ const q = &p.fs.log;
+ var at = q.head;
+ var s = q.dropped;
+ while (at + 4 <= q.buf.items.len) : (s += 1) {
+ const size = 4 + std.mem.readInt(u32, q.buf.items[at..][0..4], .little);
+ if (s == seq) {
+ const items = q.buf.items;
+ std.mem.copyForwards(u8, items[at..], items[at + size ..]);
+ q.buf.shrinkRetainingCapacity(items.len - size);
+ return;
+ }
+ at += size;
+ }
+}
+
+/// A builtin's failure: its Verbose announcement goes from the log, when
+/// `text` is that builtin's (it starts with its word) or `any`, as for a
+/// failure said while the builtin itself runs.
+pub fn dropFailedAnnouncement(p: *Pardes, text: []const u8, any: bool) void {
+ const seq = p.fs.announced_seq orelse return;
+ const word = p.fs.announced_word[0..p.fs.announced_word_len];
+ if (!any and !(std.mem.startsWith(u8, text, word) and text.len > word.len and (text[word.len] == ' ' or text[word.len] == ':'))) return;
+ p.fs.announced_seq = null;
+ dropRecord(p, seq);
+}
+
/// Drops the newest record when it is a msg saying `text` (of any pane)
/// that no follower has read: a failure its write's err record will say.
pub fn dropMessage(p: *Pardes, text: []const u8) void {