Commit 07c89c0

Eric Bower  ·  2026-10-23 21:04:42 -0400 EDT
parent 770eb5f
chore: update to zig 0.17
16 files changed,  +153, -112
▶ M Dockerfile
+1, -1
jump to top
......@@ -2,7 +2,7 @@ FROM debian:12
22
33 RUN apt-get update && apt-get install -y curl git bats coreutils python3 && rm -rf /var/lib/apt/lists/*
44
5-ARG ZIG_VERSION=0.16.0
5+ARG ZIG_VERSION=0.17.0
66 # `uname -m` already reports the names zig uses in its tarballs (x86_64,
77 # aarch64), so it needs no mapping.
88 RUN ARCH="$(uname -m)" && \
▶ M build.zig
+39, -1
jump to top
......@@ -1,4 +1,5 @@
11 const std = @import("std");
2+const Translator = @import("translate_c").Translator;
23 const build_zig_zon = @import("build.zig.zon");
34
45 const linux_targets: []const std.Target.Query = &.{
......@@ -26,11 +27,24 @@ pub fn build(b: *std.Build) void {
2627 options.addOption([]const u8, "ghostty_version", ghostty_ver);
2728 options.addOption(bool, "has_daemon", enable_daemon);
2829
30+ const translate_c = b.dependency("translate_c", .{});
31+ const translator: Translator = .init(translate_c, .{
32+ .c_source_file = b.path("src/c.h"),
33+ .target = target,
34+ .optimize = optimize,
35+ });
36+
2937 const exe_mod = b.createModule(.{
3038 .root_source_file = b.path("src/main.zig"),
3139 .target = target,
3240 .optimize = optimize,
3341 .link_libc = true,
42+ .imports = &.{
43+ .{
44+ .name = "cross",
45+ .module = translator.mod,
46+ },
47+ },
3448 });
3549 exe_mod.addOptions("build_options", options);
3650
......@@ -56,6 +70,12 @@ pub fn build(b: *std.Build) void {
5670 .target = target,
5771 .optimize = optimize,
5872 .link_libc = true,
73+ .imports = &.{
74+ .{
75+ .name = "cross",
76+ .module = translator.mod,
77+ },
78+ },
5979 });
6080
6181 zmx_pkg_mod.addOptions("build_options", options);
......@@ -79,6 +99,12 @@ pub fn build(b: *std.Build) void {
7999 .target = target,
80100 .optimize = optimize,
81101 .link_libc = true,
102+ .imports = &.{
103+ .{
104+ .name = "cross",
105+ .module = translator.mod,
106+ },
107+ },
82108 });
83109 ex_mod.addImport("zmx", zmx_pkg_mod);
84110 const ex_exe = b.addExecutable(.{ .name = ex.name, .root_module = ex_mod });
......@@ -101,7 +127,7 @@ pub fn build(b: *std.Build) void {
101127 b.installArtifact(exe);
102128 const run_cmd = b.addRunArtifact(exe);
103129 run_cmd.step.dependOn(b.getInstallStep());
104- if (b.args) |args| run_cmd.addArgs(args);
130+ run_cmd.addPassthruArgs();
105131 run_step.dependOn(&run_cmd.step);
106132 }
107133 }
......@@ -114,6 +140,12 @@ pub fn build(b: *std.Build) void {
114140 .target = target,
115141 .optimize = optimize,
116142 .link_libc = true,
143+ .imports = &.{
144+ .{
145+ .name = "cross",
146+ .module = translator.mod,
147+ },
148+ },
117149 });
118150 test_module.addOptions("build_options", options);
119151 const test_dep = b.dependency("ghostty", .{
......@@ -170,6 +202,12 @@ pub fn build(b: *std.Build) void {
170202 .target = resolved,
171203 .optimize = .ReleaseSafe,
172204 .link_libc = true,
205+ .imports = &.{
206+ .{
207+ .name = "cross",
208+ .module = translator.mod,
209+ },
210+ },
173211 });
174212 release_mod.addOptions("build_options", options);
175213
+7, -3
jump to top
......@@ -2,11 +2,15 @@
22 .name = .zmx,
33 .version = "0.8.1",
44 .fingerprint = 0x28aad87005052b4e, // Changing this has security and trust implications.
5- .minimum_zig_version = "0.16.0",
5+ .minimum_zig_version = "0.17.0",
66 .dependencies = .{
77 .ghostty = .{
8- .url = "git+https://github.com/ghostty-org/ghostty#8af6897c0afc63037a8a3efee4162a380e3a4572",
9- .hash = "ghostty-1.3.2-dev-5UdBC4FtYAV-PdFOt-gceWieTHLri0H4ztHtd6Tr4dGj",
8+ .url = "git+https://github.com/ghostty-org/ghostty#22f100c6367045bb5fc86172f837047dee2f7670",
9+ .hash = "ghostty-1.3.2-dev-5UdBC57IhQX5QCxEHr_MlUcomZtBUMVoo9BwUBIAtkln",
10+ },
11+ .translate_c = .{
12+ .url = "git+https://codeberg.org/ziglang/translate-c?ref=zig-0.17.x#cfac21f3199b2b02ce3fd7db652aa456421fe4ab",
13+ .hash = "translate_c-2.0.2-Q_BUWvBNBwDnyehSiuAJmdFcMYHYGA-Jc3KiYdrV2Dqx",
1014 },
1115 },
1216 .paths = .{
▶ A src/c.h
+30, -0
jump to top
......@@ -0,0 +1,30 @@
1+#ifndef MY_C_H
2+#define MY_C_H
3+
4+#include <stdlib.h>
5+#include <unistd.h>
6+#include <termios.h>
7+
8+#if defined(__APPLE__)
9+ #include <sys/ioctl.h>
10+ #include <sys/types.h>
11+
12+ // Declare forkpty manually for macOS cross-compilation environments
13+ // where util.h might be missing from sysroot.
14+ pid_t forkpty(int *amaster, char *name, const struct termios *termp, const struct winsize *winp);
15+
16+#elif defined(__OpenBSD__)
17+ #include <sys/types.h>
18+ #include <sys/ioctl.h>
19+ #include <util.h>
20+
21+#elif defined(__FreeBSD__)
22+ #include <libutil.h>
23+
24+#else
25+ #include <sys/ioctl.h>
26+ #include <pty.h>
27+
28+#endif
29+
30+#endif // MY_C_H
▶ M src/cfg.zig
+7, -7
jump to top
......@@ -5,7 +5,7 @@ pub const Cfg = @This();
55
66 const std = @import("std");
77 const lib_posix = @import("posix.zig");
8-const cross = @import("cross.zig");
8+const cross = @import("cross");
99
1010 socket_dir: []const u8,
1111 log_dir: []const u8,
......@@ -113,8 +113,8 @@ test "Cfg.init uses default modes when env vars are not set" {
113113 const alloc = std.testing.allocator;
114114
115115 // Ensure they are not set
116- _ = cross.c.unsetenv("ZMX_DIR_MODE");
117- _ = cross.c.unsetenv("ZMX_LOG_MODE");
116+ _ = cross.unsetenv("ZMX_DIR_MODE");
117+ _ = cross.unsetenv("ZMX_LOG_MODE");
118118
119119 var cfg = try Cfg.init(alloc, std.testing.io);
120120 defer cfg.deinit(alloc);
......@@ -127,11 +127,11 @@ test "Cfg.init uses custom modes from env vars" {
127127 const alloc = std.testing.allocator;
128128
129129 // Set custom octal values
130- _ = cross.c.setenv("ZMX_DIR_MODE", "770", 1);
131- _ = cross.c.setenv("ZMX_LOG_MODE", "660", 1);
130+ _ = cross.setenv("ZMX_DIR_MODE", "770", 1);
131+ _ = cross.setenv("ZMX_LOG_MODE", "660", 1);
132132 defer {
133- _ = cross.c.unsetenv("ZMX_DIR_MODE");
134- _ = cross.c.unsetenv("ZMX_LOG_MODE");
133+ _ = cross.unsetenv("ZMX_DIR_MODE");
134+ _ = cross.unsetenv("ZMX_LOG_MODE");
135135 }
136136
137137 var cfg = try Cfg.init(alloc, std.testing.io);
+12, -12
jump to top
......@@ -12,7 +12,7 @@ const Cfg = @import("cfg.zig");
1212 const util = @import("util.zig");
1313 const label = @import("label.zig");
1414 const lib_posix = @import("posix.zig");
15-const cross = @import("cross.zig");
15+const cross = @import("cross");
1616 const signal = @import("signal.zig");
1717 const loop = @import("loop.zig");
1818 const Daemon = if (has_daemon) loop.Daemon else struct {};
......@@ -163,25 +163,25 @@ pub fn attach(alloc: Allocator, io: Io, name: []const u8, opts: AttachOptions) !
163163
164164 const client_sock = try socket.sessionConnect(socket_path);
165165
166- var orig_termios: cross.c.termios = undefined;
167- const stdin_is_tty = cross.c.tcgetattr(lib_posix.STDIN_FILENO, &orig_termios) == 0;
166+ var orig_termios: cross.termios = undefined;
167+ const stdin_is_tty = cross.tcgetattr(lib_posix.STDIN_FILENO, &orig_termios) == 0;
168168 const restore_seq = "\x1bc\x1b]110\x1b\\\x1b]111\x1b\\\x1b]112\x1b\\";
169169
170170 defer {
171171 if (stdin_is_tty) {
172- _ = cross.c.tcsetattr(lib_posix.STDIN_FILENO, cross.c.TCSAFLUSH, &orig_termios);
172+ _ = cross.tcsetattr(lib_posix.STDIN_FILENO, cross.TCSAFLUSH, &orig_termios);
173173 }
174174 _ = lib_posix.write(lib_posix.STDOUT_FILENO, restore_seq) catch {};
175175 }
176176
177177 if (stdin_is_tty) {
178178 var raw_termios = orig_termios;
179- cross.c.cfmakeraw(&raw_termios);
180- raw_termios.c_cc[cross.c.VLNEXT] = cross.c._POSIX_VDISABLE;
181- raw_termios.c_cc[cross.c.VQUIT] = cross.c._POSIX_VDISABLE;
182- raw_termios.c_cc[cross.c.VMIN] = 1;
183- raw_termios.c_cc[cross.c.VTIME] = 0;
184- _ = cross.c.tcsetattr(lib_posix.STDIN_FILENO, cross.c.TCSANOW, &raw_termios);
179+ cross.cfmakeraw(&raw_termios);
180+ raw_termios.c_cc[cross.VLNEXT] = cross._POSIX_VDISABLE;
181+ raw_termios.c_cc[cross.VQUIT] = cross._POSIX_VDISABLE;
182+ raw_termios.c_cc[cross.VMIN] = 1;
183+ raw_termios.c_cc[cross.VTIME] = 0;
184+ _ = cross.tcsetattr(lib_posix.STDIN_FILENO, cross.TCSANOW, &raw_termios);
185185 }
186186
187187 const clear_seq = "\x1b[0m\x1b[2J\x1b[H";
......@@ -748,12 +748,12 @@ pub fn historyRange(alloc: Allocator, io: Io, name: []const u8, format: HistoryF
748748 const reply_tag: ipc.Tag = if (scrollback_rows != null) .Capture else .History;
749749 if (scrollback_rows) |rows| {
750750 var request = std.mem.zeroes(ipc.Capture);
751- request.format = @intFromEnum(format);
751+ request.format = @backingInt(format);
752752 request.rows = rows;
753753 try ipc.send(fd, .Capture, std.mem.asBytes(&request));
754754 try ipc.send(fd, .Info, "");
755755 } else {
756- const format_byte = [_]u8{@intFromEnum(format)};
756+ const format_byte = [_]u8{@backingInt(format)};
757757 try ipc.send(fd, .History, &format_byte);
758758 }
759759
+0, -39
jump to top
......@@ -1,39 +0,0 @@
1-const builtin = @import("builtin");
2-const std = @import("std");
3-
4-pub const c = switch (builtin.os.tag) {
5- .macos => @cImport({
6- @cInclude("sys/ioctl.h"); // ioctl and constants
7- @cInclude("termios.h");
8- @cInclude("stdlib.h");
9- @cInclude("unistd.h");
10- }),
11- .openbsd => @cImport({
12- @cInclude("sys/types.h");
13- @cInclude("sys/ioctl.h");
14- @cInclude("termios.h");
15- @cInclude("util.h"); // forkpty()
16- @cInclude("stdlib.h");
17- @cInclude("unistd.h");
18- }),
19- .freebsd => @cImport({
20- @cInclude("termios.h"); // ioctl and constants
21- @cInclude("libutil.h"); // openpty()
22- @cInclude("stdlib.h");
23- @cInclude("unistd.h");
24- }),
25- else => @cImport({
26- @cInclude("sys/ioctl.h"); // ioctl and constants
27- @cInclude("pty.h");
28- @cInclude("stdlib.h");
29- @cInclude("unistd.h");
30- }),
31-};
32-
33-// Manually declare forkpty for macOS since util.h is not available during cross-compilation
34-pub const forkpty = if (builtin.os.tag == .macos)
35- struct {
36- extern "c" fn forkpty(master_fd: *c_int, name: ?[*:0]u8, termp: ?*const c.struct_termios, winp: ?*const c.struct_winsize) c_int;
37- }.forkpty
38-else
39- c.forkpty;
+19, -11
jump to top
......@@ -5,7 +5,7 @@ const socket = @import("socket.zig");
55 const ipc = @import("ipc.zig");
66 const assert = std.debug.assert;
77 const log = @import("log.zig");
8-const cross = @import("cross.zig");
8+const cross = @import("cross");
99
1010 const Cmd = struct {
1111 file: [*:0]const u8,
......@@ -19,7 +19,8 @@ pub fn createCmdZ(def_shell: []const u8, is_task_mode: bool, command: ?[]const [
1919 if (cmd_args.len > 0) {
2020 const argv = try gpa.allocSentinel(?[*:0]const u8, cmd_args.len, null);
2121 for (cmd_args, 0..) |arg, i| {
22- argv[i] = try gpa.dupeZ(u8, arg);
22+ const s = try gpa.dupeSentinel(u8, arg, 0);
23+ argv[i] = s.ptr;
2324 }
2425 return .{
2526 .file = argv[0].?,
......@@ -28,17 +29,24 @@ pub fn createCmdZ(def_shell: []const u8, is_task_mode: bool, command: ?[]const [
2829 }
2930 }
3031
31- const z = try std.fmt.allocPrintSentinel(gpa, "{s}", .{def_shell}, 0);
32- const shell: [:0]const u8 = if (is_task_mode) "bash" else z;
32+ const shell: [:0]const u8 = if (is_task_mode)
33+ "bash"
34+ else
35+ try gpa.dupeSentinel(u8, def_shell, 0);
3336
3437 // Use "-shellname" as argv[0] to signal login shell (traditional method)
35- const login_shell = try std.fmt.allocPrintSentinel(gpa, "-{s}", .{std.fs.path.basename(shell)}, 0);
38+ const login_shell = try std.fmt.allocPrintSentinel(
39+ gpa,
40+ "-{s}",
41+ .{std.fs.path.basename(shell)},
42+ 0,
43+ );
3644 const argv = try gpa.allocSentinel(?[*:0]const u8, 1, null);
3745 argv[0] = login_shell.ptr;
3846
3947 return .{
4048 .file = shell,
41- .argv_ptr = argv,
49+ .argv_ptr = argv.ptr,
4250 };
4351 }
4452
......@@ -63,14 +71,14 @@ fn exec(sesh_name: []const u8, cmd: Cmd) !noreturn {
6371 .{sesh_name},
6472 0,
6573 );
66- _ = cross.c.putenv(session_env.ptr);
74+ _ = cross.putenv(session_env.ptr);
6775
68- if (cross.c.getenv("TERM")) |term_env| {
76+ if (cross.getenv("TERM")) |term_env| {
6977 if (std.mem.eql(u8, std.mem.span(term_env), "dumb")) {
70- _ = cross.c.putenv(@constCast("TERM=xterm-256color"));
78+ _ = cross.putenv(@constCast("TERM=xterm-256color"));
7179 }
7280 } else {
73- _ = cross.c.putenv(@constCast("TERM=xterm-256color"));
81+ _ = cross.putenv(@constCast("TERM=xterm-256color"));
7482 }
7583
7684 const err = lib_posix.execvpeZ(cmd.file, cmd.argv_ptr, std.c.environ);
......@@ -89,7 +97,7 @@ pub const PtyInfo = struct {
8997 /// This is the second fork in the double-fork technique explained in the
9098 /// daemonize() comment.
9199 pub fn spawnPty(sesh_name: []const u8, cmd: Cmd, size: ipc.Resize) !PtyInfo {
92- var ws: cross.c.struct_winsize = .{
100+ var ws: cross.struct_winsize = .{
93101 .ws_row = size.rows,
94102 .ws_col = size.cols,
95103 .ws_xpixel = size.xpixel,
▶ M src/ipc.zig
+10, -10
jump to top
......@@ -1,5 +1,5 @@
11 const std = @import("std");
2-const cross = @import("cross.zig");
2+const cross = @import("cross");
33 const socket = @import("socket.zig");
44 const lib_posix = @import("posix.zig");
55
......@@ -39,7 +39,7 @@ pub const Tag = enum(u8) {
3939 };
4040
4141 comptime {
42- if (@typeInfo(Tag).@"enum".is_exhaustive) @compileError(
42+ if (@typeInfo(Tag).@"enum".mode == .exhaustive) @compileError(
4343 "ipc.Tag must stay non-exhaustive -- old daemons rely on `_` to ignore unknown tags",
4444 );
4545 }
......@@ -57,7 +57,7 @@ pub const Resize = extern struct {
5757 xpixel: u16 = 0,
5858 ypixel: u16 = 0,
5959
60- pub fn winsize(self: Resize) cross.c.struct_winsize {
60+ pub fn winsize(self: Resize) cross.struct_winsize {
6161 return .{
6262 .ws_row = self.rows,
6363 .ws_col = self.cols,
......@@ -72,25 +72,25 @@ pub const Resize = extern struct {
7272 /// screen; zero returns only the screen.
7373 pub const Capture = extern struct {
7474 format: u8,
75- _reserved: [3]u8 = .{0} ** 3,
75+ _reserved: [3]u8 = @splat(0),
7676 rows: u32,
7777 };
7878
7979 pub fn getTerminalSize(fd: i32) Resize {
80- var ws: cross.c.struct_winsize = undefined;
81- if (cross.c.ioctl(fd, cross.c.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
80+ var ws: cross.struct_winsize = undefined;
81+ if (cross.ioctl(fd, cross.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
8282 return .{ .rows = ws.ws_row, .cols = ws.ws_col, .xpixel = ws.ws_xpixel, .ypixel = ws.ws_ypixel };
8383 }
8484 inline for (.{ lib_posix.STDOUT_FILENO, lib_posix.STDIN_FILENO, lib_posix.STDERR_FILENO }) |fallback_fd| {
8585 if (fallback_fd != fd) {
86- if (cross.c.ioctl(fallback_fd, cross.c.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
86+ if (cross.ioctl(fallback_fd, cross.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
8787 return .{ .rows = ws.ws_row, .cols = ws.ws_col, .xpixel = ws.ws_xpixel, .ypixel = ws.ws_ypixel };
8888 }
8989 }
9090 }
9191 if (lib_posix.open("/dev/tty", .{ .ACCMODE = .RDWR }, 0)) |tty_fd| {
9292 defer lib_posix.close(tty_fd);
93- if (cross.c.ioctl(tty_fd, cross.c.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
93+ if (cross.ioctl(tty_fd, cross.TIOCGWINSZ, &ws) == 0 and ws.ws_row > 0 and ws.ws_col > 0) {
9494 return .{ .rows = ws.ws_row, .cols = ws.ws_col, .xpixel = ws.ws_xpixel, .ypixel = ws.ws_ypixel };
9595 }
9696 } else |_| {}
......@@ -115,7 +115,7 @@ pub const Info = extern struct {
115115 task_ended_at: u64,
116116 task_exit_code: u8,
117117 protocol_version: u8 = PROTOCOL_VERSION,
118- _reserved: [6]u8 = .{0} ** 6,
118+ _reserved: [6]u8 = @splat(0),
119119 };
120120
121121 pub fn send(fd: i32, tag: Tag, data: []const u8) !void {
......@@ -357,7 +357,7 @@ test "Tag wire values are frozen" {
357357 .{ Tag.LabelSet, 15 }, .{ Tag.LabelClear, 16 }, .{ Tag.LabelData, 17 },
358358 .{ Tag.Send, 18 }, .{ Tag.EnvGet, 19 }, .{ Tag.EnvSet, 20 },
359359 .{ Tag.EnvData, 21 }, .{ Tag.Capture, 22 }, .{ Tag.Unsupported, 255 },
360- }) |p| try std.testing.expectEqual(@as(u8, p[1]), @intFromEnum(p[0]));
360+ }) |p| try std.testing.expectEqual(@as(u8, p[1]), @backingInt(p[0]));
361361 }
362362
363363 pub fn roundTripForTag(
▶ M src/log.zig
+2, -2
jump to top
......@@ -1,5 +1,5 @@
11 const std = @import("std");
2-const cross = @import("cross.zig");
2+const cross = @import("cross");
33
44 pub var log_system = LogSystem{};
55
......@@ -40,7 +40,7 @@ pub const LogSystem = struct {
4040 // between our length() check and seekTo(), causing us to overwrite
4141 // recent parent entries. lseek(fd, 0, SEEK_END) is atomic — it
4242 // always positions at the true end of file at seek time.
43- const new_pos = cross.c.lseek(file.handle, 0, cross.c.SEEK_END);
43+ const new_pos = cross.lseek(file.handle, 0, cross.SEEK_END);
4444 if (new_pos == -1) {
4545 std.Io.File.close(file, self.io);
4646 return error.SeekFailed;
▶ M src/loop.zig
+10, -10
jump to top
......@@ -2,7 +2,7 @@ const std = @import("std");
22 const ipc = @import("ipc.zig");
33 const log = @import("log.zig");
44 const util = @import("util.zig");
5-const cross = @import("cross.zig");
5+const cross = @import("cross");
66 const socket = @import("socket.zig");
77 const label = @import("label.zig");
88 const lib_posix = @import("posix.zig");
......@@ -19,7 +19,7 @@ const ghostty_vt = terminal.ghostty_vt;
1919 pub fn clientLoop(client_sock_fd: i32, env_str: []const u8) !ClientResult {
2020 std.log.info("client loop fd={d}", .{client_sock_fd});
2121 const gpa: std.mem.Allocator = blk: {
22- if (builtin.mode == .Debug) {
22+ if (builtin.mode == .debug) {
2323 const GPA = std.heap.DebugAllocator(.{});
2424 const Static = struct {
2525 var gpa: GPA = .{};
......@@ -31,7 +31,7 @@ pub fn clientLoop(client_sock_fd: i32, env_str: []const u8) !ClientResult {
3131 defer lib_posix.close(client_sock_fd);
3232
3333 try signal.openSignalPipe();
34- signal.installWakeHandler(@intFromEnum(lib_posix.SIG.WINCH));
34+ signal.installWakeHandler(@backingInt(lib_posix.SIG.WINCH));
3535
3636 // Make socket non-blocking to avoid blocking on writes
3737 var sock_flags = try lib_posix.fcntl(client_sock_fd, lib_posix.F.GETFL, 0);
......@@ -240,7 +240,7 @@ fn daemonLoop(daemon: *Daemon, gpa: std.mem.Allocator, io: std.Io, server_sock_f
240240 std.log.info("daemon started session={s} pty_fd={d}", .{ daemon.session_name, pty_fd });
241241
242242 try signal.openSignalPipe();
243- signal.installWakeHandler(@intFromEnum(lib_posix.SIG.TERM));
243+ signal.installWakeHandler(@backingInt(lib_posix.SIG.TERM));
244244 var poll_fds = try std.ArrayList(lib_posix.pollfd).initCapacity(gpa, 8);
245245 defer poll_fds.deinit(gpa);
246246
......@@ -508,7 +508,7 @@ fn daemonLoop(daemon: *Daemon, gpa: std.mem.Allocator, io: std.Io, server_sock_f
508508 _ => {
509509 std.log.warn(
510510 "ignoring unknown IPC tag={d}",
511- .{@intFromEnum(msg.header.tag)},
511+ .{@backingInt(msg.header.tag)},
512512 );
513513 ipc.appendMessage(gpa, &client.write_buf, .Unsupported, "") catch {};
514514 client.has_pending_output = true;
......@@ -838,7 +838,7 @@ pub const Daemon = struct {
838838 }
839839
840840 const gpa: std.mem.Allocator = blk: {
841- if (builtin.mode == .Debug) {
841+ if (builtin.mode == .debug) {
842842 const GPA = std.heap.DebugAllocator(.{});
843843 const Static = struct {
844844 var gpa: GPA = .{};
......@@ -1028,7 +1028,7 @@ pub const Daemon = struct {
10281028 // only resize if leader
10291029 if (is_leader) {
10301030 var ws = resize.winsize();
1031- _ = cross.c.ioctl(pty_fd, cross.c.TIOCSWINSZ, &ws);
1031+ _ = cross.ioctl(pty_fd, cross.TIOCSWINSZ, &ws);
10321032
10331033 // On re-attach, deliver SIGWINCH to the foreground process group so
10341034 // incremental renderers (Ink, Claude Code, etc.) know to repaint.
......@@ -1036,7 +1036,7 @@ pub const Daemon = struct {
10361036 // was unchanged, the kernel suppressed it, so signal the pgrp explicitly.
10371037 if (self.has_pty_output) {
10381038 var pgrp: lib_posix.pid_t = 0;
1039- if (cross.c.ioctl(pty_fd, cross.c.TIOCGPGRP, &pgrp) == 0 and pgrp > 0) {
1039+ if (cross.ioctl(pty_fd, cross.TIOCGPGRP, &pgrp) == 0 and pgrp > 0) {
10401040 lib_posix.kill(-pgrp, .WINCH) catch {};
10411041 }
10421042 }
......@@ -1062,7 +1062,7 @@ pub const Daemon = struct {
10621062
10631063 const resize = std.mem.bytesToValue(ipc.Resize, payload);
10641064 var ws = resize.winsize();
1065- _ = cross.c.ioctl(pty_fd, cross.c.TIOCSWINSZ, &ws);
1065+ _ = cross.ioctl(pty_fd, cross.TIOCSWINSZ, &ws);
10661066 try resizeTerm(gpa, term, resize.cols, resize.rows);
10671067 std.log.debug("resize rows={d} cols={d}", .{ resize.rows, resize.cols });
10681068 }
......@@ -1158,7 +1158,7 @@ pub const Daemon = struct {
11581158 ) !void {
11591159 self.setPwd(term);
11601160 const format: util.HistoryFormat = if (payload.len > 0)
1161- @enumFromInt(payload[0])
1161+ @fromBackingInt(@intCast(payload[0]))
11621162 else
11631163 .plain;
11641164 if (util.serializeTerminal(gpa, term, format)) |output| {
+6, -6
jump to top
......@@ -395,11 +395,11 @@ pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
395395 /// the system function call whose errno value is intended to be observed.
396396 fn errno(rc: anytype) E {
397397 if (use_libc) {
398- return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
398+ return if (rc == -1) @fromBackingInt(@intCast(std.c._errno().*)) else .SUCCESS;
399399 }
400400 const signed: isize = @bitCast(rc);
401401 const int = if (signed > -4096 and signed < 0) -signed else 0;
402- return @enumFromInt(int);
402+ return @fromBackingInt(@intCast(int));
403403 }
404404
405405 fn setSockFlags(sock: socket_t, flags: u32) !void {
......@@ -1008,10 +1008,10 @@ pub fn exit(status: u8) noreturn {
10081008 // exit() is only available if exitBootServices() has not been called yet.
10091009 // This call to exit should not fail, so we catch-ignore errors.
10101010 if (uefi.system_table.boot_services) |bs| {
1011- bs.exit(uefi.handle, @enumFromInt(status), null) catch {};
1011+ bs.exit(uefi.handle, @fromBackingInt(@intCast(status)), null) catch {};
10121012 }
10131013 // If we can't exit, reboot the system instead.
1014- uefi.system_table.runtime_services.resetSystem(.cold, @enumFromInt(status), null);
1014+ uefi.system_table.runtime_services.resetSystem(.cold, @fromBackingInt(@intCast(status)), null);
10151015 }
10161016 system.exit(status);
10171017 }
......@@ -1244,7 +1244,7 @@ pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {
12441244 /// and you get an unexpected error.
12451245 fn unexpectedErrno(err: E) UnexpectedError {
12461246 if (unexpected_error_tracing) {
1247- std.debug.print("unexpected errno: {d}\n", .{@intFromEnum(err)});
1247+ std.debug.print("unexpected errno: {d}\n", .{@backingInt(err)});
12481248 std.debug.dumpCurrentStackTrace(std.debug.StackUnwindOptions{});
12491249 }
12501250 return error.Unexpected;
......@@ -1255,7 +1255,7 @@ fn unexpectedErrno(err: E) UnexpectedError {
12551255 /// If this happens the fix is to add the error code to the corresponding
12561256 /// switch expression, possibly introduce a new error in the error set, and
12571257 /// send a patch to Zig.
1258-const unexpected_error_tracing = builtin.mode == .Debug and switch (builtin.zig_backend) {
1258+const unexpected_error_tracing = builtin.mode == .debug and switch (builtin.zig_backend) {
12591259 .stage2_llvm, .stage2_x86_64 => true,
12601260 else => false,
12611261 };
+1, -1
jump to top
......@@ -21,7 +21,7 @@ pub fn installWakeHandler(sig: u6) void {
2121 .mask = lib_posix.sigemptyset(),
2222 .flags = lib_posix.SA.SIGINFO,
2323 };
24- lib_posix.sigaction(@as(lib_posix.SIG, @enumFromInt(sig)), &act, null);
24+ lib_posix.sigaction(@as(lib_posix.SIG, @fromBackingInt(@intCast(sig))), &act, null);
2525 }
2626
2727 pub fn ignoreSigpipe() void {
+4, -4
jump to top
......@@ -181,7 +181,7 @@ test "getSocketPath succeeds for paths within limit" {
181181
182182 test "getSocketPath returns NameTooLong when path exceeds limit" {
183183 const alloc = std.testing.allocator;
184- const dir = [_]u8{'d'} ** (max_socket_path_len - 2);
184+ const dir: [max_socket_path_len - 2]u8 = @splat('d');
185185 const dir_slice: []const u8 = &dir;
186186
187187 const ok = try getSocketPath(alloc, dir_slice, "x");
......@@ -194,7 +194,7 @@ test "getSocketPath returns NameTooLong when path exceeds limit" {
194194
195195 test "getSocketPath returns NameTooLong for empty dir with oversized name" {
196196 const alloc = std.testing.allocator;
197- const name = [_]u8{'n'} ** (max_socket_path_len);
197+ const name: [max_socket_path_len]u8 = @splat('n');
198198 const name_slice: []const u8 = &name;
199199 const err = getSocketPath(alloc, "", name_slice);
200200 try std.testing.expectError(error.NameTooLong, err);
......@@ -205,11 +205,11 @@ test "maxSessionNameLen computes correct dynamic limit" {
205205 const short_max = maxSessionNameLen(short_dir).?;
206206 try std.testing.expectEqual(max_socket_path_len - short_dir.len - 1, short_max);
207207
208- const full_dir = [_]u8{'f'} ** max_socket_path_len;
208+ const full_dir: [max_socket_path_len]u8 = @splat('f');
209209 const full_dir_slice: []const u8 = &full_dir;
210210 try std.testing.expectEqual(@as(?usize, null), maxSessionNameLen(full_dir_slice));
211211
212- const tight_dir = [_]u8{'t'} ** (max_socket_path_len - 2);
212+ const tight_dir: [max_socket_path_len - 2]u8 = @splat('t');
213213 const tight_dir_slice: []const u8 = &tight_dir;
214214 try std.testing.expectEqual(@as(?usize, 1), maxSessionNameLen(tight_dir_slice));
215215 }
+1, -1
jump to top
......@@ -104,7 +104,7 @@ fn writeDynamicColor(
104104 ) void {
105105 const c = dynamic.override orelse return;
106106 writer.print("\x1b]{d};rgb:{x:0>2}/{x:0>2}/{x:0>2}\x1b\\", .{
107- @intFromEnum(kind), c.r, c.g, c.b,
107+ @backingInt(kind), c.r, c.g, c.b,
108108 }) catch |err| {
109109 std.log.warn("failed to format dynamic color err={s}", .{@errorName(err)});
110110 };
▶ M src/util.zig
+4, -4
jump to top
......@@ -8,7 +8,7 @@ pub const serializeTerminal = if (has_daemon) terminal.serializeTerminal else st
88 pub const serializeTerminalRange = if (has_daemon) terminal.serializeTerminalRange else struct {};
99 const ipc = @import("ipc.zig");
1010 const socket = @import("socket.zig");
11-const cross = @import("cross.zig");
11+const cross = @import("cross");
1212 const label = @import("label.zig");
1313 const lib_posix = @import("posix.zig");
1414 const testing = std.testing;
......@@ -1122,11 +1122,11 @@ test "isCtrlBackslash xterm modifyOtherKeys" {
11221122 }
11231123
11241124 test "isDetachKeyDisabled" {
1125- _ = cross.c.unsetenv("ZMX_NO_DETACH_KEY");
1125+ _ = cross.unsetenv("ZMX_NO_DETACH_KEY");
11261126 try testing.expect(!isDetachKeyDisabled());
11271127
1128- _ = cross.c.setenv("ZMX_NO_DETACH_KEY", "1", 1);
1129- defer _ = cross.c.unsetenv("ZMX_NO_DETACH_KEY");
1128+ _ = cross.setenv("ZMX_NO_DETACH_KEY", "1", 1);
1129+ defer _ = cross.unsetenv("ZMX_NO_DETACH_KEY");
11301130 try testing.expect(isDetachKeyDisabled());
11311131 }
11321132