summaryrefslogtreecommitdiff
path: root/src/Messages.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Messages.zig')
-rw-r--r--src/Messages.zig53
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);
}