Compare commits

...

3 commits

Author SHA1 Message Date
0f9824d08b
wip: macos 2024-07-10 22:40:29 +02:00
045955d5db
wip: macos 2024-07-10 22:39:45 +02:00
54c43bab5d
wip: macos 2024-07-04 14:53:40 +02:00
5 changed files with 150 additions and 10 deletions

View file

@ -49,6 +49,7 @@ pub fn main() !void {
}; };
const shell = env.get("SHELL") orelse "bash"; const shell = env.get("SHELL") orelse "bash";
const argv = [_][]const u8{shell}; const argv = [_][]const u8{shell};
std.debug.print("executing: {s}\n", .{shell});
var vt = try vaxis.widgets.Terminal.init( var vt = try vaxis.widgets.Terminal.init(
alloc, alloc,
&argv, &argv,
@ -61,9 +62,10 @@ pub fn main() !void {
var redraw: bool = false; var redraw: bool = false;
while (true) { while (true) {
std.time.sleep(8 * std.time.ns_per_ms); std.debug.print("inside while loop before resize\n", .{});
// try vt events first // try vt events first
while (vt.tryEvent()) |event| { while (vt.tryEvent()) |event| {
std.debug.print("inside stryEventloop \n", .{});
redraw = true; redraw = true;
switch (event) { switch (event) {
.bell => {}, .bell => {},
@ -74,6 +76,7 @@ pub fn main() !void {
} }
} }
while (loop.tryEvent()) |event| { while (loop.tryEvent()) |event| {
std.debug.print("inside loop.tryEvent\n", .{});
redraw = true; redraw = true;
switch (event) { switch (event) {
.key_press => |key| { .key_press => |key| {

View file

@ -17,6 +17,23 @@ pid: ?std.posix.pid_t = null,
env_map: *const std.process.EnvMap, env_map: *const std.process.EnvMap,
pty: Pty, pty: Pty,
const TIOCSCTTY = if (builtin.os.tag == .macos) 536900705 else c.TIOCSCTTY;
const TIOCSWINSZ = if (builtin.os.tag == .macos) 2148037735 else c.TIOCSWINSZ;
const TIOCGWINSZ = if (builtin.os.tag == .macos) 1074295912 else c.TIOCGWINSZ;
// extern "c" fn setsid() std.c.pid_t;
const c = struct {
usingnamespace switch (builtin.os.tag) {
.macos => @cImport({
@cInclude("sys/ioctl.h"); // ioctl and constants
@cInclude("util.h");
@cInclude("unistd.h"); // openpty()
}),
else => @cImport({
@cInclude("sys/ioctl.h"); // ioctl and constants
@cInclude("pty.h");
}),
};
};
pub fn spawn(self: *Command, allocator: std.mem.Allocator) !void { pub fn spawn(self: *Command, allocator: std.mem.Allocator) !void {
var arena_allocator = std.heap.ArenaAllocator.init(allocator); var arena_allocator = std.heap.ArenaAllocator.init(allocator);
@ -31,12 +48,26 @@ pub fn spawn(self: *Command, allocator: std.mem.Allocator) !void {
const pid = try std.posix.fork(); const pid = try std.posix.fork();
if (pid == 0) { if (pid == 0) {
// we are the child std.posix.close(self.pty.pty);
_ = std.os.linux.setsid(); std.debug.print("inside child\n", .{});
if (c.setsid() != 0) return error.SetSid;
// set the controlling terminal std.debug.print("setting up io for tty\n", .{});
var u: c_uint = std.posix.STDIN_FILENO; var u: c_uint = std.posix.STDIN_FILENO;
if (posix.system.ioctl(self.pty.tty, posix.T.IOCSCTTY, @intFromPtr(&u)) != 0) return error.IoctlError;
if (c.ioctl(self.pty.tty, TIOCSCTTY, @intFromPtr(&u)) != 0) return error.IoctlError;
// switch (builtin.os.tag) {
// .linux => {},
// .ios, .macos => {
// // Mac doesn't support dup3 so we use dup2. We purposely clear
// // CLO_ON_EXEC for this fd.
// const flags = try posix.fcntl(self.pty.tty, posix.F.GETFD, 0);
// if (flags & posix.FD_CLOEXEC != 0) {
// _ = try posix.fcntl(self.pty.tty, posix.F.SETFD, flags & ~@as(u32, posix.FD_CLOEXEC));
// }
// },
// else => @compileError("unsupported platform"),
// }
// set up io // set up io
try posix.dup2(self.pty.tty, std.posix.STDIN_FILENO); try posix.dup2(self.pty.tty, std.posix.STDIN_FILENO);
@ -51,13 +82,17 @@ pub fn spawn(self: *Command, allocator: std.mem.Allocator) !void {
} }
// exec // exec
const err = std.posix.execvpeZ(argv_buf.ptr[0].?, argv_buf.ptr, envp); _ = std.posix.execvpeZ(argv_buf.ptr[0].?, argv_buf.ptr, envp) catch null;
_ = err catch {};
//return error.ExecFailed;
// const err = std.posix.execvpeZ("/bin/zsh", "/bin/zsh", envp);
// _ = err catch {};
} }
// we are the parent // we are the parent
self.pid = @intCast(pid); self.pid = @intCast(pid);
_ = posix.waitpid(pid, 0);
std.debug.print("waitpid in parent\n", .{});
if (!Terminal.global_sigchild_installed) { if (!Terminal.global_sigchild_installed) {
Terminal.global_sigchild_installed = true; Terminal.global_sigchild_installed = true;
var act = posix.Sigaction{ var act = posix.Sigaction{

View file

@ -7,6 +7,25 @@ const Winsize = @import("../../main.zig").Winsize;
const posix = std.posix; const posix = std.posix;
extern "c" fn setsid() std.c.pid_t;
const c = struct {
usingnamespace switch (builtin.os.tag) {
.macos => @cImport({
@cInclude("sys/ioctl.h"); // ioctl and constants
@cInclude("util.h"); // openpty()
}),
else => @cImport({
@cInclude("sys/ioctl.h"); // ioctl and constants
@cInclude("pty.h");
}),
};
};
const TIOCSCTTY = if (builtin.os.tag == .macos) 536900705 else c.TIOCSCTTY;
const TIOCSWINSZ = if (builtin.os.tag == .macos) 2148037735 else c.TIOCSWINSZ;
const TIOCGWINSZ = if (builtin.os.tag == .macos) 1074295912 else c.TIOCGWINSZ;
pty: posix.fd_t, pty: posix.fd_t,
tty: posix.fd_t, tty: posix.fd_t,
@ -14,6 +33,7 @@ tty: posix.fd_t,
pub fn init() !Pty { pub fn init() !Pty {
switch (builtin.os.tag) { switch (builtin.os.tag) {
.linux => return openPtyLinux(), .linux => return openPtyLinux(),
.macos => return openPtyMacos(),
else => @compileError("unsupported os"), else => @compileError("unsupported os"),
} }
} }
@ -32,10 +52,75 @@ pub fn setSize(self: Pty, ws: Winsize) !void {
.ws_xpixel = @truncate(ws.x_pixel), .ws_xpixel = @truncate(ws.x_pixel),
.ws_ypixel = @truncate(ws.y_pixel), .ws_ypixel = @truncate(ws.y_pixel),
}; };
if (posix.system.ioctl(self.pty, posix.T.IOCSWINSZ, @intFromPtr(&_ws)) != 0) if (c.ioctl(self.pty, TIOCSWINSZ, @intFromPtr(&_ws)) != 0)
return error.SetWinsizeError; return error.SetWinsizeError;
} }
fn openPtyMacos2() !Pty {
const p = try posix.open("/dev/ptmx", .{ .ACCMODE = .RDWR, .NOCTTY = true }, 0);
errdefer posix.close(p);
// unlockpt
// var n: c_uint = 0;
if (c.ioctl(p, c.TIOCPTYUNLK) != 0) return error.IoctlError;
// ptsname
if (c.ioctl(p, c.TIOCPTYGRANT) != 0) return error.IoctlError;
var buf: [128]u8 = undefined;
// var buf2: [128]u8 = undefined;
if (c.ioctl(p, c.TIOCPTYGNAME, &buf) != 0) return error.IoctlError;
const sname = buf[0 .. 13 - 1];
// std.debug.print("sizeof buf: {d}", .{buf.len});
// const sname = try std.fmt.bufPrint(&buf2, "{s}", .{buf});
std.debug.print("slave name: {s}\n", .{sname});
// const sname = try std.fmt.bufPrint(&buf, "/dev/pts/{d}", .{n});
// std.log.err("pts: {s}", .{sname});
const t = try posix.open(sname, .{ .ACCMODE = .RDWR, .NOCTTY = true }, 0);
std.debug.print("posix opened : {s}\n", .{sname});
var attrs: c.termios = undefined;
if (c.tcgetattr(p, &attrs) != 0)
return error.OpenptyFailed;
attrs.c_iflag |= c.IUTF8;
if (c.tcsetattr(p, c.TCSANOW, &attrs) != 0)
return error.OpenptyFailed;
return .{
.pty = p,
.tty = t,
};
}
fn openPtyMacos() !Pty {
var master_fd: posix.fd_t = undefined;
var slave_fd: posix.fd_t = undefined;
if (c.openpty(
&master_fd,
&slave_fd,
null,
null,
null,
) < 0)
return error.OpenptyFailed;
errdefer {
_ = posix.system.close(master_fd);
_ = posix.system.close(slave_fd);
}
var attrs: c.termios = undefined;
if (c.tcgetattr(master_fd, &attrs) != 0)
return error.OpenptyFailed;
attrs.c_iflag |= c.IUTF8;
if (c.tcsetattr(master_fd, c.TCSANOW, &attrs) != 0)
return error.OpenptyFailed;
return .{
.pty = master_fd,
.tty = slave_fd,
};
}
fn openPtyLinux() !Pty { fn openPtyLinux() !Pty {
const p = try posix.open("/dev/ptmx", .{ .ACCMODE = .RDWR, .NOCTTY = true }, 0); const p = try posix.open("/dev/ptmx", .{ .ACCMODE = .RDWR, .NOCTTY = true }, 0);
errdefer posix.close(p); errdefer posix.close(p);

View file

@ -94,8 +94,12 @@ pub fn init(
unicode: *const vaxis.Unicode, unicode: *const vaxis.Unicode,
opts: Options, opts: Options,
) !Terminal { ) !Terminal {
if (opts.initial_working_directory) |pwd| {
if (!std.fs.path.isAbsolute(pwd)) return error.InvalidWorkingDirectory;
}
const pty = try Pty.init(); const pty = try Pty.init();
try pty.setSize(opts.winsize); try pty.setSize(opts.winsize);
std.debug.print("set size done\n", .{});
const cmd: Command = .{ const cmd: Command = .{
.argv = argv, .argv = argv,
.env_map = env, .env_map = env,
@ -155,6 +159,7 @@ pub fn deinit(self: *Terminal) void {
} }
pub fn spawn(self: *Terminal) !void { pub fn spawn(self: *Terminal) !void {
std.debug.print("inside spawn", .{});
if (self.thread != null) return; if (self.thread != null) return;
self.back_screen = &self.back_screen_pri; self.back_screen = &self.back_screen_pri;
@ -259,6 +264,7 @@ fn anyReader(self: *const Terminal) std.io.AnyReader {
/// process the output from the command on the pty /// process the output from the command on the pty
fn run(self: *Terminal) !void { fn run(self: *Terminal) !void {
std.debug.print("inside run\n", .{});
var parser: Parser = .{ var parser: Parser = .{
.buf = try std.ArrayList(u8).initCapacity(self.allocator, 128), .buf = try std.ArrayList(u8).initCapacity(self.allocator, 128),
}; };
@ -268,6 +274,7 @@ fn run(self: *Terminal) !void {
var reader = std.io.bufferedReader(self.anyReader()); var reader = std.io.bufferedReader(self.anyReader());
while (!self.should_quit) { while (!self.should_quit) {
std.debug.print("inside while loop\n", .{});
const event = try parser.parseReader(&reader); const event = try parser.parseReader(&reader);
self.back_mutex.lock(); self.back_mutex.lock();
defer self.back_mutex.unlock(); defer self.back_mutex.unlock();
@ -275,8 +282,10 @@ fn run(self: *Terminal) !void {
if (!self.dirty and self.event_queue.tryPush(.redraw)) if (!self.dirty and self.event_queue.tryPush(.redraw))
self.dirty = true; self.dirty = true;
std.debug.print("before switch event\n", .{});
switch (event) { switch (event) {
.print => |str| { .print => |str| {
std.debug.print("inside print event\n", .{});
var iter = grapheme.Iterator.init(str, &self.unicode.grapheme_data); var iter = grapheme.Iterator.init(str, &self.unicode.grapheme_data);
while (iter.next()) |g| { while (iter.next()) |g| {
const gr = g.bytes(str); const gr = g.bytes(str);
@ -287,6 +296,7 @@ fn run(self: *Terminal) !void {
}, },
.c0 => |b| try self.handleC0(b), .c0 => |b| try self.handleC0(b),
.escape => |esc| { .escape => |esc| {
std.debug.print("inside escape event\n", .{});
const final = esc[esc.len - 1]; const final = esc[esc.len - 1];
switch (final) { switch (final) {
'B' => {}, // TODO: handle charsets 'B' => {}, // TODO: handle charsets
@ -700,6 +710,7 @@ fn run(self: *Terminal) !void {
} }
inline fn handleC0(self: *Terminal, b: ansi.C0) !void { inline fn handleC0(self: *Terminal, b: ansi.C0) !void {
std.debug.print("inside handlec0\n", .{});
switch (b) { switch (b) {
.NUL, .SOH, .STX => {}, .NUL, .SOH, .STX => {},
.EOT => {}, // we send EOT to quit the read thread .EOT => {}, // we send EOT to quit the read thread
@ -716,6 +727,7 @@ inline fn handleC0(self: *Terminal, b: ansi.C0) !void {
} }
pub fn setMode(self: *Terminal, mode: u16, val: bool) void { pub fn setMode(self: *Terminal, mode: u16, val: bool) void {
std.debug.print("inside setmode\n", .{});
switch (mode) { switch (mode) {
7 => self.mode.autowrap = val, 7 => self.mode.autowrap = val,
25 => self.mode.cursor = val, 25 => self.mode.cursor = val,

View file

@ -0,0 +1,5 @@
info(loop): pixel mouse capability detected
info(loop): unicode capability detected
info(loop): color_scheme_updates capability detected
info(loop): kitty keyboard capability detected
info(loop): kitty graphics capability detected