diff options
Diffstat (limited to 'src/look.zig')
| -rw-r--r-- | src/look.zig | 64 |
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, + } +} |
