a73x

7367068b

feat(pty): add read/write helpers

a73x   2026-04-08 06:02

Commit message
feat(pty): add read/write helpers

src/pty.zig
Old New
@@ -52,6 +52,14 @@ pub const Pty = struct {
52 }; 52 };
53 } 53 }
54 54
55 pub fn read(self: *Pty, buf: []u8) !usize {
56 return std.posix.read(self.master_fd, buf);
57 }
58
59 pub fn write(self: *Pty, data: []const u8) !usize {
60 return std.posix.write(self.master_fd, data);
61 }
62
55 pub fn deinit(self: *Pty) void { 63 pub fn deinit(self: *Pty) void {
56 std.posix.close(self.master_fd); 64 std.posix.close(self.master_fd);
57 _ = std.c.kill(self.child_pid, std.c.SIG.TERM); 65 _ = std.c.kill(self.child_pid, std.c.SIG.TERM);
@@ -59,6 +67,41 @@ pub const Pty = struct {
59 } 67 }
60 }; 68 };
61 69
70 test "Pty.write and read echoes through shell" {
71 var pty = try Pty.spawn(.{
72 .cols = 80,
73 .rows = 24,
74 .shell = "/bin/sh",
75 });
76 defer pty.deinit();
77
78 // Give shell a moment to start
79 std.Thread.sleep(100 * std.time.ns_per_ms);
80
81 // Write a command
82 _ = try pty.write("echo hello\n");
83
84 // Drain output for up to 1 second
85 var buf: [4096]u8 = undefined;
86 var seen_hello = false;
87 const deadline = std.time.nanoTimestamp() + 1 * std.time.ns_per_s;
88 while (std.time.nanoTimestamp() < deadline) {
89 const n = pty.read(&buf) catch |err| switch (err) {
90 error.WouldBlock => {
91 std.Thread.sleep(10 * std.time.ns_per_ms);
92 continue;
93 },
94 else => return err,
95 };
96 if (n == 0) break;
97 if (std.mem.indexOf(u8, buf[0..n], "hello") != null) {
98 seen_hello = true;
99 break;
100 }
101 }
102 try std.testing.expect(seen_hello);
103 }
104
62 test "Pty.spawn launches /bin/sh and returns valid fd" { 105 test "Pty.spawn launches /bin/sh and returns valid fd" {
63 var pty = try Pty.spawn(.{ 106 var pty = try Pty.spawn(.{
64 .cols = 80, 107 .cols = 80,