diff options
Diffstat (limited to 'src/Messages.zig')
| -rw-r--r-- | src/Messages.zig | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/src/Messages.zig b/src/Messages.zig index 36cd44da..ce7a2a8c 100644 --- a/src/Messages.zig +++ b/src/Messages.zig @@ -412,9 +412,8 @@ fn logMessage(p: *Pardes, id: usize, text: []const u8) void { if (text.len == 0) return; const serial: u32 = if (p.fs.session_write) 0 else if (id < MAX_PANES) if (p.panes[id]) |pane| pane.serial else 0 else 0; const kept = text[0..@min(text.len, LoggedMessage.cap)]; - // /log hears every one: a client that retried and failed the same way - // is waiting on that second line. Only the +Messages view collapses. - ctlfs.events.noteMessage(p, serial, kept); + // /log hears every one (a failure of a ctl write as its err record). + if (!p.fs.unlogged) ctlfs.events.noteMessage(p, serial, text); if (p.messages.len > 0) { const last = &p.messages.log[(p.messages.head + limits.message_log - 1) % limits.message_log]; if (last.serial == serial and @@ -444,17 +443,40 @@ pub fn messageLog(m: *const Messages, i: usize) ?*const LoggedMessage { return &m.log[(first + i) % limits.message_log]; } -/// `<operation>: <the error in words>`: FileNotFound reads "file not found". /// What a route that would open a pane says when every slot is taken. -pub const no_pane_slots = "no pane slots: {d} max"; +/// "no space": 9ns's word for ENOSPC (it has none for ENFILE). +pub const no_pane_slots = "no space for a pane: {d} max"; +/// ...and when the column it would go in has no rows for one. +pub const no_pane_room = "no space for a pane in that column: each keeps its tag and {d} rows"; + +/// `<operation>: <the error in words>`: FileNotFound reads "file not found". +/// Why a peer could not be reached, in words, for an error of a 9P dial +/// (src/9p_io.zig, Client); null for any other error. +pub fn dialReason(err: anyerror) ?[]const u8 { + return switch (err) { + error.Dial => "no answer", + error.Timeout => "timed out", + error.Hangup => "hung up", + error.Botch => "protocol botch", + else => null, + }; +} pub fn reportError(p: *Pardes, id: usize, operation: []const u8, err: anyerror) void { var buf: [256]u8 = undefined; var w = std.Io.Writer.fixed(&buf); w.print("{s}: ", .{operation}) catch {}; + // A peer out of reach says so, not the error's name (`dial`). + if (dialReason(err)) |why| { + w.print("dial failed: {s}", .{why}) catch {}; + return reportFailure(p, id, w.buffered()); + } // Every route that opens a pane says the cap the same way. - if (err == error.NoPaneSlots) { - w.print(no_pane_slots, .{pardes.MAX_PANES}) catch {}; + if (err == error.NoPaneSlots or err == error.NoPaneRoom) { + if (err == error.NoPaneSlots) + w.print(no_pane_slots, .{pardes.MAX_PANES}) catch {} + else + w.print(no_pane_room, .{pardes.layout.min_body_rows}) catch {}; // A 9P look or exec that would open the pane fails with it too. p.fs.no_pane_slot = true; @memcpy(p.fs.ename[0..w.buffered().len], w.buffered()); @@ -480,9 +502,14 @@ pub fn clip(text: []const u8, max: usize) []const u8 { /// reportError with the words already chosen. pub fn reportFailure(p: *Pardes, id: usize, text: []const u8) void { + p.fs.failures +%= 1; + // A failure said later, when the host could not do the work (a Save's + // write): that builtin's announcement goes from the log too. + ctlfs.events.dropFailedAnnouncement(p, text, false); // A builtin a ctl write runs: its first error is also the write's, cut // between words. - if (p.fs.no_prompt and p.fs.failure_len == 0) { + const failing_write = p.fs.no_prompt or p.fs.capturing; + if (failing_write and p.fs.failure_len == 0) { const kept = if (text.len > p.fs.failure.len) clip(text, p.fs.failure.len - 3) else text; @memcpy(p.fs.failure[0..kept.len], kept); var n = kept.len; @@ -492,6 +519,16 @@ pub fn reportFailure(p: *Pardes, id: usize, text: []const u8) void { } p.fs.failure_len = @intCast(n); } + // The write fails with it, and its err record says it: no msg for it, + // and no Verbose announcement before that, so the same failure again is + // the same record again, counted (events.pushCounting). + if (failing_write) { + const serial: u32 = if (p.fs.session_write) 0 else if (id < MAX_PANES) if (p.panes[id]) |pane| pane.serial else 0 else 0; + ctlfs.events.dropAnnouncement(p, serial, text); + p.fs.unlogged = true; + defer p.fs.unlogged = false; + return setMessage(p, id, text); + } setMessage(p, id, text); } |
