diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 07:05:46 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | 1b513045336b3c7381c447ffa8c9167f8b1a5a0a (patch) | |
| tree | bf9377e7178f367c3ad0b35446f4aa9eaf9600d2 /src/ninep/events.zig | |
| parent | 96383331f09e8af3fa24f767b3c56863309723b8 (diff) | |
| download | pardes-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.zig | 38 |
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 { |
