diff options
| -rw-r--r-- | docs/detached.md | 5 | ||||
| -rw-r--r-- | src/Messages.zig | 7 | ||||
| -rw-r--r-- | src/detached/server.zig | 9 | ||||
| -rw-r--r-- | src/pardes.zig | 1 |
4 files changed, 17 insertions, 5 deletions
diff --git a/docs/detached.md b/docs/detached.md index 17c225f2..46e93fd5 100644 --- a/docs/detached.md +++ b/docs/detached.md @@ -19,8 +19,9 @@ turn a local editor into a detached session. A message stays until the next key or click dismisses it. With no frontend attached there is none to come, so a detached session drops each pane's -messages once the newest has been up `MessageLinger` on the clock, as the -editor is stepped or served over 9P; /screen then shows what is current. +messages once the newest has been up `MessageLinger` on the clock, checked +by the session's own loop between the editor's steps; /screen then shows +what is current. ## Files and transport diff --git a/src/Messages.zig b/src/Messages.zig index 0652f974..00352afe 100644 --- a/src/Messages.zig +++ b/src/Messages.zig @@ -208,7 +208,9 @@ fn nowMs() i64 { /// With no frontend attached no input dismisses a message, and a detached /// session's /screen and messages kept what was said an hour ago: each /// pane's lines go once its newest has been up `message_linger_ms`, on the -/// clock, checked as the core is stepped or served. +/// clock, checked as the core is stepped and by the detached session's loop +/// between steps -- not as a 9P request is served, since a read is answered +/// while a step is out and must change nothing. /// ponytail: a pane's older lines go with its newest, not each on its own /// clock; the render pipeline's clock will give every line its own. pub fn expireUnattended(p: *Pardes) void { @@ -570,7 +572,10 @@ test "with no frontend attached a message goes once it has lingered, on the cloc // Detached with nobody attached: past its linger it is gone, and the // line above it with it. p.unattended = true; + // A read served meanwhile changes nothing; the session's loop expires. _ = p.serveFs(.{ .tag = 1, .op = .read, .node = @intFromEnum(ctlfs.TopFile.index), .size = 64 }); + try std.testing.expect(pane.msg_len > 0); + expireUnattended(p); try std.testing.expectEqual(@as(u16, 0), pane.msg_len); try std.testing.expectEqual(@as(u8, 0), pane.msg_older_len); // A fresh one stays until its linger is up. diff --git a/src/detached/server.zig b/src/detached/server.zig index 6a4b5001..61fbe111 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -770,8 +770,10 @@ pub const Session = struct { const completed = s.ninep_wake.swap(false, .acq_rel) or drained; for (&s.clients) |*c| if (c.fd >= 0) s.flush(c); const regridded = s.reconcile(); - // Nobody attached, nobody to dismiss a message (expireUnattended). + // Nobody attached, nobody to dismiss a message: the loop expires + // them itself, between the editor's steps (expireUnattended). s.core.unattended = s.primary() == null; + pardes.Messages.expireUnattended(s.core); const now = monotonicMs(); var fds: [poll_slots]libc.pollfd = undefined; @@ -904,6 +906,11 @@ pub const Session = struct { due = if (due) |d| @min(d, at9) else at9; } } + // Unattended messages go on the clock: look again in a while. + if (s.core.unattended) for (s.core.panes) |slot| if (slot) |pane| if (pane.msg_len > 0) { + due = if (due) |d| @min(d, now + 100) else now + 100; + break; + }; const at = due orelse return null; return @intCast(@max(0, @min(at - now, std.math.maxInt(c_int)))); } diff --git a/src/pardes.zig b/src/pardes.zig index 2eab3d62..9fa747cd 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4675,7 +4675,6 @@ pub const Pardes = struct { /// that changes a pane costs a frame, which is why a round trip on a /// local socket costs microseconds and not a vsync. pub fn serveFs(p: *Pardes, req: ctlfs.Req) ctlfs.Reply { - Messages.expireUnattended(p); if (!ctlfs.changesPane(req)) return ctlfs.handle(p, req); p.needs_frame = true; p.raw_hover_intent = false; |
