summaryrefslogtreecommitdiff
path: root/src/look.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-06 18:00:54 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commit7a83d1548493b043e2e77022c1c87d348377ac7b (patch)
tree75bcac77800b13695a953a3398b5bb8a95e017dd /src/look.zig
parentde4def3548a6729b0dfd2120495a61beef8c8c2c (diff)
downloadpardes-7a83d1548493b043e2e77022c1c87d348377ac7b.tar.gz
pardes-7a83d1548493b043e2e77022c1c87d348377ac7b.zip
posix portability: linux syscalls -> libc (std.c) in one shared path. All raw std.os.linux.* call sites converted with the errno-convention flip (libc returns -1 + thread-local errno, not -errno): open/close/read/write/rename in tty.zig, gui.zig, look.zig; harness too (snapshot.zig: getcwd/mkdir/chdir/fork+waitpid/getdents64->opendir-readdir, e2e_harness.zig: clock_gettime/write/close), so the parity suite itself is POSIX-portable. Per-OS branches kept only where platforms genuinely diverge: shellCwd in look.zig (linux /proc/<pid>/cwd readlink; darwin libproc proc_pidinfo PROC_PIDVNODEPATHINFO with a hand-declared extern; other POSIX degrades to null), bash path (/usr/bin/bash on linux, /bin/bash elsewhere), TIOCSWINSZ constant (absent from std.c.T on darwin). forkpty/execv/chdir externs were already libc and are portable (fork-safety preserved: absolute-path execv, no malloc between fork and exec, initial spawns before worker threads). build.zig: forward target/optimize to the ghostty dep for native/cross (web keeps its no-target fetch), disable ghostty simd for darwin cross-builds (apple_sdk needs xcrun; scalar fallback = web config), link libutil on the BSDs. Pinned ghostty needs two one-line zig-0.16 darwin fixes, applied in the zig-pkg cache and documented in build.zig. Verified: aarch64-macos + x86_64-macos + x86_64-freebsd cross-compiles green; linux native tty + gui + web green; snapshot suite 18/18 with goldens untouched. Out of scope: gui-on-macos needs Metal shaders (SDL GPU rejects our SPIR-V there).
Diffstat (limited to 'src/look.zig')
-rw-r--r--src/look.zig64
1 files changed, 51 insertions, 13 deletions
diff --git a/src/look.zig b/src/look.zig
index 67fbf8c5..8744da24 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -8,7 +8,8 @@
//! web — there is no filesystem; only URLs mean anything, and a URL
//! opens in a new tab (the open_link effect).
const std = @import("std");
-const linux = std.os.linux;
+const builtin = @import("builtin");
+const libc = std.c;
const pardes = @import("pardes.zig");
extern "c" fn realpath(path: [*:0]const u8, resolved: [*]u8) ?[*:0]u8;
@@ -88,10 +89,9 @@ const platform_has_fs = switch (pardes.platform) {
/// true if `path` exists and is a directory (open(O_DIRECTORY), no stat needed)
fn isDir(path: [*:0]const u8) bool {
- const rc = linux.open(path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true, .CLOEXEC = true }, 0);
- const sfd: isize = @bitCast(rc);
- if (sfd < 0) return false;
- _ = linux.close(@intCast(sfd));
+ const fd = libc.open(path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true, .CLOEXEC = true });
+ if (fd < 0) return false;
+ _ = libc.close(fd);
return true;
}
@@ -101,19 +101,16 @@ pub fn readFile(gpa: std.mem.Allocator, path: []const u8) ![]u8 {
if (!platform_has_fs) return error.NoFilesystem;
var pathbuf: [4096]u8 = undefined;
const path_z = std.fmt.bufPrintSentinel(&pathbuf, "{s}", .{path}, 0) catch return error.PathTooLong;
- const rc = linux.open(path_z, .{ .ACCMODE = .RDONLY }, 0);
- const sfd: isize = @bitCast(rc);
- if (sfd < 0) return error.OpenFailed;
- const fd: i32 = @intCast(sfd);
- defer _ = linux.close(fd);
+ const fd = libc.open(path_z, .{ .ACCMODE = .RDONLY });
+ if (fd < 0) return error.OpenFailed;
+ defer _ = libc.close(fd);
var buf: std.ArrayList(u8) = .empty;
errdefer buf.deinit(gpa);
var chunk: [16384]u8 = undefined;
while (true) {
- const r = linux.read(fd, &chunk, chunk.len);
- const n: isize = @bitCast(r);
+ const n = libc.read(fd, &chunk, chunk.len);
if (n < 0) {
- if (n == -@as(isize, @intFromEnum(linux.E.INTR))) continue;
+ if (libc.errno(n) == .INTR) continue;
return error.ReadFailed;
}
if (n == 0) break;
@@ -121,3 +118,44 @@ pub fn readFile(gpa: std.mem.Allocator, path: []const u8) ![]u8 {
}
return buf.toOwnedSlice(gpa);
}
+
+// ---- shell cwd: what directory a pane's looks resolve against ----
+
+// macOS has no /proc; libproc's proc_pidinfo(PROC_PIDVNODEPATHINFO) yields the
+// cwd vnode path. Not in std.c — layout from xnu's sys/proc_info.h.
+const vnode_info_path = extern struct {
+ vi: [152]u8 align(8), // struct vnode_info: vinfo_stat + type + pad + fsid
+ path: [1024]u8, // MAXPATHLEN
+};
+const proc_vnodepathinfo = extern struct {
+ cdir: vnode_info_path,
+ rdir: vnode_info_path,
+};
+const PROC_PIDVNODEPATHINFO: c_int = 9;
+extern "c" fn proc_pidinfo(pid: c_int, flavor: c_int, arg: u64, buffer: *anyopaque, buffersize: c_int) c_int;
+
+/// Live cwd of a shell process (pane tags, look resolution). linux reads
+/// /proc/<pid>/cwd, darwin asks libproc; other POSIX systems have no cheap
+/// answer — return null and panes keep their spawn-time cwd (callers already
+/// tolerate failure: dead shells have no cwd either).
+pub fn shellCwd(pid: libc.pid_t, buf: *[1024]u8) ?[]const u8 {
+ switch (builtin.os.tag) {
+ .linux => {
+ var pbuf: [64]u8 = undefined;
+ const path = std.fmt.bufPrintSentinel(&pbuf, "/proc/{d}/cwd", .{pid}, 0) catch return null;
+ const n = libc.readlink(path, buf, buf.len);
+ if (n <= 0) return null;
+ return buf[0..@intCast(n)];
+ },
+ .macos, .ios, .tvos, .watchos, .visionos => {
+ var info: proc_vnodepathinfo = undefined;
+ const n = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &info, @sizeOf(proc_vnodepathinfo));
+ if (n < @as(c_int, @sizeOf(proc_vnodepathinfo))) return null;
+ const path = std.mem.sliceTo(&info.cdir.path, 0);
+ if (path.len == 0) return null;
+ @memcpy(buf[0..path.len], path);
+ return buf[0..path.len];
+ },
+ else => return null,
+ }
+}