diff --git a/src/client.zig b/src/client.zig index 16b9f1a..3ab19ed 100644 --- a/src/client.zig +++ b/src/client.zig @@ -181,7 +181,7 @@ pub const ClientState = struct { pty_validity: ?i64 = null, pub const RequestInfo = union(enum) { - spawn: struct { cwd: ?[]const u8 = null }, + spawn: struct { cwd: ?[]const u8 = null, cmd: ?[]const u8 = null }, attach: struct { pty_id: i64, cwd: ?[]const u8 = null }, detach, get_server_info, @@ -2395,7 +2395,7 @@ pub const App = struct { self.state.next_msgid += 1; log.info("spawnPty: sending request msgid={}", .{msgid}); - try self.state.pending_requests.put(msgid, .{ .spawn = .{ .cwd = opts.cwd } }); + try self.state.pending_requests.put(msgid, .{ .spawn = .{ .cwd = opts.cwd, .cmd = opts.cmd } }); // Build env array from current process environment var env_map = try std.process.getEnvMap(self.allocator); @@ -2409,7 +2409,9 @@ pub const App = struct { try env_array.append(self.allocator, .{ .string = env_str }); } - const num_params: usize = if (opts.cwd != null) 5 else 4; + var num_params: usize = 4; + if (opts.cwd != null) num_params += 1; + if (opts.cmd != null) num_params += 1; var map_items = try self.allocator.alloc(msgpack.Value.KeyValue, num_params); defer self.allocator.free(map_items); @@ -2417,8 +2419,13 @@ pub const App = struct { map_items[1] = .{ .key = .{ .string = "cols" }, .value = .{ .unsigned = opts.cols } }; map_items[2] = .{ .key = .{ .string = "attach" }, .value = .{ .boolean = opts.attach } }; map_items[3] = .{ .key = .{ .string = "env" }, .value = .{ .array = env_array.items } }; + var idx: usize = 4; if (opts.cwd) |cwd| { - map_items[4] = .{ .key = .{ .string = "cwd" }, .value = .{ .string = cwd } }; + map_items[idx] = .{ .key = .{ .string = "cwd" }, .value = .{ .string = cwd } }; + idx += 1; + } + if (opts.cmd) |cmd| { + map_items[idx] = .{ .key = .{ .string = "cmd" }, .value = .{ .string = cmd } }; } const params = msgpack.Value{ .map = map_items }; diff --git a/src/server.zig b/src/server.zig index 4d835bf..43b05c7 100644 --- a/src/server.zig +++ b/src/server.zig @@ -2056,13 +2056,14 @@ const Server = struct { /// Timestamp (ms since epoch) when server started - used to detect server restarts start_time_ms: i64 = 0, - fn parseSpawnPtyParams(params: msgpack.Value) struct { size: pty.Winsize, attach: bool, cwd: ?[]const u8, env: ?[]const msgpack.Value, macos_option_as_alt: key_encode.OptionAsAlt } { + fn parseSpawnPtyParams(params: msgpack.Value) struct { size: pty.Winsize, attach: bool, cwd: ?[]const u8, env: ?[]const msgpack.Value, macos_option_as_alt: key_encode.OptionAsAlt, cmd: ?[]const u8 } { var rows: u16 = 24; var cols: u16 = 80; var attach: bool = false; var cwd: ?[]const u8 = null; var env: ?[]const msgpack.Value = null; var macos_option_as_alt: key_encode.OptionAsAlt = .false; + var cmd: ?[]const u8 = null; if (params == .map) { for (params.map) |kv| { @@ -2079,6 +2080,8 @@ const Server = struct { env = kv.value.array; } else if (std.mem.eql(u8, kv.key.string, "macos_option_as_alt")) { macos_option_as_alt = parseMacosOptionAsAlt(kv.value); + } else if (std.mem.eql(u8, kv.key.string, "cmd") and kv.value == .string) { + cmd = kv.value.string; } } } @@ -2094,6 +2097,7 @@ const Server = struct { .cwd = cwd, .env = env, .macos_option_as_alt = macos_option_as_alt, + .cmd = cmd, }; } @@ -2261,6 +2265,22 @@ const Server = struct { try self.sendRedraw(self.loop, pty_instance, msg, client); } + // Write initial command to PTY if specified + if (parsed.cmd) |cmd| { + log.info("Writing initial command to PTY {}: {s}", .{ pty_id, cmd }); + const cmd_with_newline = try std.fmt.allocPrint(self.allocator, "{s}\n", .{cmd}); + defer self.allocator.free(cmd_with_newline); + + var total_written: usize = 0; + while (total_written < cmd_with_newline.len) { + const written = posix.write(process.master, cmd_with_newline[total_written..]) catch |err| { + log.warn("Failed to write initial command to PTY {}: {}", .{ pty_id, err }); + break; + }; + total_written += written; + } + } + log.info("Created PTY {} with PID {}", .{ pty_id, process.pid }); return msgpack.Value{ .unsigned = pty_id }; diff --git a/src/ui.zig b/src/ui.zig index d0214a9..aac4679 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -97,6 +97,7 @@ pub const UI = struct { cols: u16, attach: bool, cwd: ?[]const u8 = null, + cmd: ?[]const u8 = null, }; pub const InitError = struct { @@ -481,6 +482,10 @@ pub const UI = struct { if (lua.isString(-1)) opts.cwd = lua.toString(-1) catch null; lua.pop(1); + _ = lua.getField(1, "cmd"); + if (lua.isString(-1)) opts.cmd = lua.toString(-1) catch null; + lua.pop(1); + cb(ui.spawn_ctx, opts) catch |err| { lua.raiseErrorStr("Failed to spawn: %s", .{@errorName(err).ptr}); };