diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 22:38:16 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 6f42f51cd652e189408eace598f99ec25b9542f8 (patch) | |
| tree | 633d074c637cc25f3cb851d88414ff9e982e6fa6 | |
| parent | 7e8e2655567cab1c28597f44d0aec79e46b0deb8 (diff) | |
| download | pardes-6f42f51cd652e189408eace598f99ec25b9542f8.tar.gz pardes-6f42f51cd652e189408eace598f99ec25b9542f8.zip | |
The hosts' Save, Dump and DumpThemes writes and their shell reaper are host_io's, once, where the tty, the gui and the detached session each had a copy
writeFile, writeDump and dumpThemes were byte-for-byte the same in tty.zig, gui.zig and detached/server.zig but for how each reaches its core, and the gui's and the session's reapers the same but for a pid <= 0 against == 0 (a pid is never negative there). Each vtable entry is now a line calling host_io's. ttyTaken, fgName, killJob and ptyResize stay each shell's: they are already one call to host_io each, and what differs is how a shell reaches its pty (an optional with a file, an optional with an fd, a bounds-checked array). macos.zig keeps its copies (no macOS build here to check it). No behaviour changes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
| -rw-r--r-- | src/detached/server.zig | 42 | ||||
| -rw-r--r-- | src/gui/gui.zig | 45 | ||||
| -rw-r--r-- | src/host_io.zig | 52 | ||||
| -rw-r--r-- | src/tty/tty.zig | 26 |
4 files changed, 66 insertions, 99 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig index de26db13..d8379793 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -587,24 +587,11 @@ pub const Session = struct { fn writeFile(ctx: ?*anyopaque, pane: u8, path: []const u8, bytes: []const u8) void { const s = of(ctx); - filesystem.write(s.core, path, bytes) catch |err| - return s.core.saveFailed(pane, path, err); - if (s.core.panes[pane]) |pn| if (pn.file) |f| if (std.mem.eql(u8, f.path, path)) { - if (s.watches[pane]) |*w| if (w.serial == pn.serial) switch (w.generation) { - .text => w.generation = .{ .text = std.hash.Wyhash.hash(0, bytes) }, - .pdf => {}, - }; - }; - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "saved", path)); + host_io.writeFile(s.core, &s.watches, pane, path, bytes); } fn writeDump(ctx: ?*anyopaque, bytes: []const u8) void { - const s = of(ctx); - var pbuf: [1024:0]u8 = undefined; - const path = pardes.dump.outPath(&pbuf, s.core.settings.dump_dir.get()) orelse return s.core.dumpFailed(s.core.settings.dump_dir.get(), error.NoDumpDirectory); - filesystem.write(s.core, path, bytes) catch |err| return s.core.dumpFailed(path, err); - s.core.setLastDump(path); + host_io.writeDump(of(ctx).core, bytes); } fn watchFile(ctx: ?*anyopaque, pane: u8, _: []const u8, on: bool, mode: pardes.WatchMode) void { @@ -621,14 +608,7 @@ pub const Session = struct { fn dumpThemes(ctx: ?*anyopaque, pane: u8) void { const s = of(ctx); - const config_dir = s.core.opts.config_dir orelse return; - const out_dir = pardes.config.User.dumpThemes(s.io, s.gpa, config_dir, pardes.themes) catch |err| { - s.core.reportError(pane, "dump themes", err); - return; - }; - defer s.gpa.free(out_dir); - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "dumped themes", out_dir)); + host_io.dumpThemes(s.core, s.io, s.gpa, pane); } fn setClipboard(ctx: ?*anyopaque, text: []const u8) void { @@ -761,20 +741,8 @@ pub const Session = struct { fn harvest(s: *Session) void { const now = monotonicMs(); - for (&s.retired_shells) |*shell| reapShell(&shell.pid, &shell.kill_at, now); - for (&s.ptys) |*pty| if (pty.fd < 0) reapShell(&pty.pid, &pty.kill_at, now); - } - - fn reapShell(pid: *posix.pid_t, kill_at: *i64, now: i64) void { - if (pid.* == 0) return; - const result = libc.waitpid(pid.*, null, libc.W.NOHANG); - if (result > 0 or (result < 0 and libc.errno(result) == .CHILD)) { - pid.* = 0; - kill_at.* = 0; - } else if (kill_at.* != 0 and now >= kill_at.*) { - _ = libc.kill(pid.*, libc.SIG.KILL); - kill_at.* = 0; - } + for (&s.retired_shells) |*shell| host_io.reapRetired(&shell.pid, &shell.kill_at, now); + for (&s.ptys) |*pty| if (pty.fd < 0) host_io.reapRetired(&pty.pid, &pty.kill_at, now); } fn inotify(s: *Session) c_int { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 8b100cd8..8fd8d360 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -4060,9 +4060,9 @@ const Shell = struct { fn reap(s: *Shell) void { const now = shellClock(); - for (&s.retired_shells) |*child| reapShell(&child.pid, &child.kill_at, now); + for (&s.retired_shells) |*child| host_io.reapRetired(&child.pid, &child.kill_at, now); for (s.ptys) |*slot| if (slot.*) |*pt| if (pt.fd < 0) { - reapShell(&pt.pid, &pt.kill_at, now); + host_io.reapRetired(&pt.pid, &pt.kill_at, now); if (pt.pid == 0) slot.* = null; }; } @@ -4085,7 +4085,7 @@ const Shell = struct { _ = libc.close(pt.fd); pt.fd = -1; const now = shellClock(); - reapShell(&pt.pid, &pt.kill_at, now); + host_io.reapRetired(&pt.pid, &pt.kill_at, now); if (pt.pid == 0) { s.ptys[pane] = null; return; @@ -4662,25 +4662,11 @@ fn killJob(ctx: ?*anyopaque, pane: u8) bool { fn writeFile(ctx: ?*anyopaque, pane: u8, path: []const u8, bytes: []const u8) void { const s = shellOf(ctx); - filesystem.write(s.core, path, bytes) catch |err| - return s.core.saveFailed(pane, path, err); - if (s.core.panes[pane]) |pane_state| if (pane_state.file) |f| { - if (std.mem.eql(u8, f.path, path)) - if (s.watches[pane]) |*w| if (w.serial == pane_state.serial) switch (w.generation) { - .text => w.generation = .{ .text = std.hash.Wyhash.hash(0, bytes) }, - .pdf => {}, - }; - }; - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "saved", path)); + host_io.writeFile(s.core, s.watches, pane, path, bytes); } fn writeDump(ctx: ?*anyopaque, bytes: []const u8) void { - const s = shellOf(ctx); - var pbuf: [1024:0]u8 = undefined; - const path = pardes.dump.outPath(&pbuf, s.core.settings.dump_dir.get()) orelse return s.core.dumpFailed(s.core.settings.dump_dir.get(), error.NoDumpDirectory); - filesystem.write(s.core, path, bytes) catch |err| return s.core.dumpFailed(path, err); - s.core.setLastDump(path); + host_io.writeDump(shellOf(ctx).core, bytes); } fn watchFile(ctx: ?*anyopaque, pane: u8, _: []const u8, on: bool, mode: pardes.WatchMode) void { @@ -4704,14 +4690,7 @@ fn watchTheme(ctx: ?*anyopaque, generation: u32, on: bool) void { fn dumpThemes(ctx: ?*anyopaque, pane: u8) void { const s = shellOf(ctx); - const config_dir = s.core.opts.config_dir orelse return; - const out_dir = config.User.dumpThemes(s.io, s.gpa, config_dir, pardes.themes) catch |err| { - s.core.reportError(pane, "dump themes", err); - return; - }; - defer s.gpa.free(out_dir); - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "dumped themes", out_dir)); + host_io.dumpThemes(s.core, s.io, s.gpa, pane); } fn putClipboard(gpa: std.mem.Allocator, text: []const u8) void { @@ -4826,18 +4805,6 @@ fn shellClock() i64 { return @as(i64, ts.sec) * std.time.ms_per_s + @divTrunc(ts.nsec, std.time.ns_per_ms); } -fn reapShell(pid: *libc.pid_t, kill_at: *i64, now: i64) void { - if (pid.* <= 0) return; - const result = libc.waitpid(pid.*, null, libc.W.NOHANG); - if (result > 0 or (result < 0 and libc.errno(result) == .CHILD)) { - pid.* = 0; - kill_at.* = 0; - } else if (kill_at.* != 0 and now >= kill_at.*) { - _ = libc.kill(pid.*, libc.SIG.KILL); - kill_at.* = 0; - } -} - fn accumulateWheelDelta(pending: f32, raw_y: f32) f32 { if (!std.math.isFinite(raw_y)) return pending; const next = pending - raw_y; diff --git a/src/host_io.zig b/src/host_io.zig index 05ccca09..ac25e63c 100644 --- a/src/host_io.zig +++ b/src/host_io.zig @@ -5,6 +5,7 @@ const libc = std.c; const pardes = @import("pardes.zig"); const ninep_io = @import("9p_io.zig"); const filesystem = @import("fs.zig"); +const file_watch = @import("file_watch.zig"); pub const Host = struct { ctx: ?*anyopaque = null, @@ -2522,3 +2523,54 @@ test "a full-screen program takes the tty until it quits" { } if (ran == 0) return error.SkipZigTest; } + +// ---- what every host's vtable does alike ---- + +/// A Save's write: the file written through the core's filesystem, the +/// pane's watch told the new text is the editor's own (so it is no outside +/// change), and "saved" said on the pane. +pub fn writeFile(core: *pardes.Pardes, watches: *file_watch.Table, pane: u8, path: []const u8, bytes: []const u8) void { + filesystem.write(core, path, bytes) catch |err| + return core.saveFailed(pane, path, err); + if (core.panes[pane]) |pn| if (pn.file) |f| if (std.mem.eql(u8, f.path, path)) { + if (watches[pane]) |*w| if (w.serial == pn.serial) switch (w.generation) { + .text => w.generation = .{ .text = std.hash.Wyhash.hash(0, bytes) }, + .pdf => {}, + }; + }; + var mbuf: [256]u8 = undefined; + core.setMessage(pane, pardes.Messages.Message.stamp(&mbuf, "saved", path)); +} + +/// A Dump's write, into the DumpDir. +pub fn writeDump(core: *pardes.Pardes, bytes: []const u8) void { + var pbuf: [1024:0]u8 = undefined; + const path = pardes.dump.outPath(&pbuf, core.settings.dump_dir.get()) orelse return core.dumpFailed(core.settings.dump_dir.get(), error.NoDumpDirectory); + filesystem.write(core, path, bytes) catch |err| return core.dumpFailed(path, err); + core.setLastDump(path); +} + +/// DumpThemes: the built-in themes written below the config directory. +pub fn dumpThemes(core: *pardes.Pardes, io: std.Io, gpa: std.mem.Allocator, pane: u8) void { + const config_dir = core.opts.config_dir orelse return; + const out_dir = pardes.config.User.dumpThemes(io, gpa, config_dir, pardes.themes) catch |err| { + core.reportError(pane, "dump themes", err); + return; + }; + defer gpa.free(out_dir); + var mbuf: [256]u8 = undefined; + core.setMessage(pane, pardes.Messages.Message.stamp(&mbuf, "dumped themes", out_dir)); +} + +/// A retired shell reaped once it has exited, killed once its grace is up. +pub fn reapRetired(pid: *std.c.pid_t, kill_at: *i64, now: i64) void { + if (pid.* <= 0) return; + const result = std.c.waitpid(pid.*, null, std.c.W.NOHANG); + if (result > 0 or (result < 0 and std.c.errno(result) == .CHILD)) { + pid.* = 0; + kill_at.* = 0; + } else if (kill_at.* != 0 and now >= kill_at.*) { + _ = std.c.kill(pid.*, std.c.SIG.KILL); + kill_at.* = 0; + } +} diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 3441bc29..ef7f2761 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -1791,24 +1791,11 @@ const Shell = struct { fn writeFile(ctx: ?*anyopaque, pane: u8, path: []const u8, bytes: []const u8) void { const s = of(ctx); - filesystem.write(s.core, path, bytes) catch |err| - return s.core.saveFailed(pane, path, err); - if (s.core.panes[pane]) |pn| if (pn.file) |f| if (std.mem.eql(u8, f.path, path)) { - if (s.watches[pane]) |*w| if (w.serial == pn.serial) switch (w.generation) { - .text => w.generation = .{ .text = std.hash.Wyhash.hash(0, bytes) }, - .pdf => {}, - }; - }; - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "saved", path)); + host_io.writeFile(s.core, &s.watches, pane, path, bytes); } fn writeDump(ctx: ?*anyopaque, bytes: []const u8) void { - const s = of(ctx); - var pbuf: [1024:0]u8 = undefined; - const path = pardes.dump.outPath(&pbuf, s.core.settings.dump_dir.get()) orelse return s.core.dumpFailed(s.core.settings.dump_dir.get(), error.NoDumpDirectory); - filesystem.write(s.core, path, bytes) catch |err| return s.core.dumpFailed(path, err); - s.core.setLastDump(path); + host_io.writeDump(of(ctx).core, bytes); } fn watchFile(ctx: ?*anyopaque, pane: u8, _: []const u8, on: bool, mode: pardes.WatchMode) void { @@ -1825,14 +1812,7 @@ const Shell = struct { fn dumpThemes(ctx: ?*anyopaque, pane: u8) void { const s = of(ctx); - const config_dir = s.core.opts.config_dir orelse return; - const out_dir = pardes.config.User.dumpThemes(s.io, s.gpa, config_dir, pardes.themes) catch |err| { - s.core.reportError(pane, "dump themes", err); - return; - }; - defer s.gpa.free(out_dir); - var mbuf: [256]u8 = undefined; - s.core.setMessage(pane, message.stamp(&mbuf, "dumped themes", out_dir)); + host_io.dumpThemes(s.core, s.io, s.gpa, pane); } fn setClipboard(ctx: ?*anyopaque, text: []const u8) void { |
