mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
command: stylistic changes
This commit is contained in:
252
src/Command.zig
252
src/Command.zig
@ -112,145 +112,153 @@ pub fn start(self: *Command, alloc: Allocator) !void {
|
|||||||
defer arena_allocator.deinit();
|
defer arena_allocator.deinit();
|
||||||
const arena = arena_allocator.allocator();
|
const arena = arena_allocator.allocator();
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
switch (builtin.os.tag) {
|
||||||
const application_w = try std.unicode.utf8ToUtf16LeWithNull(arena, self.path);
|
.windows => try self.startWindows(arena),
|
||||||
const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeWithNull(arena, cwd) else null;
|
else => try self.startPosix(arena),
|
||||||
const command_line_w = if (self.args.len > 0) b: {
|
}
|
||||||
const command_line = try windowsCreateCommandLine(arena, self.args);
|
}
|
||||||
break :b try std.unicode.utf8ToUtf16LeWithNull(arena, command_line);
|
|
||||||
} else null;
|
|
||||||
const env_w = if (self.env) |env_map| try createWindowsEnvBlock(arena, env_map) else null;
|
|
||||||
|
|
||||||
const any_null_fd = self.stdin == null or self.stdout == null or self.stderr == null;
|
fn startPosix(self: *Command, arena: Allocator) !void {
|
||||||
const null_fd = if (any_null_fd) try windows.OpenFile(
|
// Null-terminate all our arguments
|
||||||
&[_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' },
|
const pathZ = try arena.dupeZ(u8, self.path);
|
||||||
.{
|
const argsZ = try arena.allocSentinel(?[*:0]u8, self.args.len, null);
|
||||||
.access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE,
|
for (self.args, 0..) |arg, i| argsZ[i] = (try arena.dupeZ(u8, arg)).ptr;
|
||||||
.share_access = windows.FILE_SHARE_READ,
|
|
||||||
.creation = windows.OPEN_EXISTING,
|
|
||||||
.io_mode = .blocking,
|
|
||||||
},
|
|
||||||
) else null;
|
|
||||||
defer if (null_fd) |fd| std.os.close(fd);
|
|
||||||
|
|
||||||
// TODO: In the case of having FDs instead of pty, need to set up attributes such that the
|
// Determine our env vars
|
||||||
// child process only inherits these handles, then set bInheritsHandles below.
|
const envp = if (self.env) |env_map|
|
||||||
|
(try createNullDelimitedEnvMap(arena, env_map)).ptr
|
||||||
|
else if (builtin.link_libc)
|
||||||
|
std.c.environ
|
||||||
|
else
|
||||||
|
@compileError("missing env vars");
|
||||||
|
|
||||||
const attribute_list, const stdin, const stdout, const stderr = if (self.pseudo_console) |pseudo_console| b: {
|
// Fork
|
||||||
var attribute_list_size: usize = undefined;
|
const pid = try std.os.fork();
|
||||||
_ = windows.exp.kernel32.InitializeProcThreadAttributeList(
|
if (pid != 0) {
|
||||||
null,
|
// Parent, return immediately.
|
||||||
1,
|
self.pid = @intCast(pid);
|
||||||
0,
|
return;
|
||||||
&attribute_list_size,
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const attribute_list_buf = try arena.alloc(u8, attribute_list_size);
|
// We are the child.
|
||||||
if (windows.exp.kernel32.InitializeProcThreadAttributeList(
|
|
||||||
attribute_list_buf.ptr,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
&attribute_list_size,
|
|
||||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
|
||||||
|
|
||||||
if (windows.exp.kernel32.UpdateProcThreadAttribute(
|
// Setup our file descriptors for std streams.
|
||||||
attribute_list_buf.ptr,
|
if (self.stdin) |f| try setupFd(f.handle, os.STDIN_FILENO);
|
||||||
0,
|
if (self.stdout) |f| try setupFd(f.handle, os.STDOUT_FILENO);
|
||||||
windows.exp.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
if (self.stderr) |f| try setupFd(f.handle, os.STDERR_FILENO);
|
||||||
pseudo_console,
|
|
||||||
@sizeOf(windows.exp.HPCON),
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
|
||||||
|
|
||||||
break :b .{ attribute_list_buf.ptr, null, null, null };
|
// Setup our working directory
|
||||||
} else b: {
|
if (self.cwd) |cwd| try os.chdir(cwd);
|
||||||
const stdin = if (self.stdin) |f| f.handle else null_fd.?;
|
|
||||||
const stdout = if (self.stdout) |f| f.handle else null_fd.?;
|
|
||||||
const stderr = if (self.stderr) |f| f.handle else null_fd.?;
|
|
||||||
break :b .{ null, stdin, stdout, stderr };
|
|
||||||
};
|
|
||||||
|
|
||||||
var startup_info_ex = windows.exp.STARTUPINFOEX{
|
// If the user requested a pre exec callback, call it now.
|
||||||
.StartupInfo = .{
|
if (self.pre_exec) |f| f(self);
|
||||||
.cb = if (attribute_list != null) @sizeOf(windows.exp.STARTUPINFOEX) else @sizeOf(windows.STARTUPINFOW),
|
|
||||||
.hStdError = stderr,
|
|
||||||
.hStdOutput = stdout,
|
|
||||||
.hStdInput = stdin,
|
|
||||||
.dwFlags = windows.STARTF_USESTDHANDLES,
|
|
||||||
.lpReserved = null,
|
|
||||||
.lpDesktop = null,
|
|
||||||
.lpTitle = null,
|
|
||||||
.dwX = 0,
|
|
||||||
.dwY = 0,
|
|
||||||
.dwXSize = 0,
|
|
||||||
.dwYSize = 0,
|
|
||||||
.dwXCountChars = 0,
|
|
||||||
.dwYCountChars = 0,
|
|
||||||
.dwFillAttribute = 0,
|
|
||||||
.wShowWindow = 0,
|
|
||||||
.cbReserved2 = 0,
|
|
||||||
.lpReserved2 = null,
|
|
||||||
},
|
|
||||||
.lpAttributeList = attribute_list,
|
|
||||||
};
|
|
||||||
|
|
||||||
var flags: windows.DWORD = windows.exp.CREATE_UNICODE_ENVIRONMENT;
|
// Finally, replace our process.
|
||||||
if (attribute_list != null) flags |= windows.exp.EXTENDED_STARTUPINFO_PRESENT;
|
_ = std.os.execveZ(pathZ, argsZ, envp) catch null;
|
||||||
|
}
|
||||||
|
|
||||||
var process_information: windows.PROCESS_INFORMATION = undefined;
|
fn startWindows(self: *Command, arena: Allocator) !void {
|
||||||
if (windows.exp.kernel32.CreateProcessW(
|
const application_w = try std.unicode.utf8ToUtf16LeWithNull(arena, self.path);
|
||||||
application_w.ptr,
|
const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeWithNull(arena, cwd) else null;
|
||||||
if (command_line_w) |w| w.ptr else null,
|
const command_line_w = if (self.args.len > 0) b: {
|
||||||
|
const command_line = try windowsCreateCommandLine(arena, self.args);
|
||||||
|
break :b try std.unicode.utf8ToUtf16LeWithNull(arena, command_line);
|
||||||
|
} else null;
|
||||||
|
const env_w = if (self.env) |env_map| try createWindowsEnvBlock(arena, env_map) else null;
|
||||||
|
|
||||||
|
const any_null_fd = self.stdin == null or self.stdout == null or self.stderr == null;
|
||||||
|
const null_fd = if (any_null_fd) try windows.OpenFile(
|
||||||
|
&[_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' },
|
||||||
|
.{
|
||||||
|
.access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE,
|
||||||
|
.share_access = windows.FILE_SHARE_READ,
|
||||||
|
.creation = windows.OPEN_EXISTING,
|
||||||
|
.io_mode = .blocking,
|
||||||
|
},
|
||||||
|
) else null;
|
||||||
|
defer if (null_fd) |fd| std.os.close(fd);
|
||||||
|
|
||||||
|
// TODO: In the case of having FDs instead of pty, need to set up
|
||||||
|
// attributes such that the child process only inherits these handles,
|
||||||
|
// then set bInheritsHandles below.
|
||||||
|
|
||||||
|
const attribute_list, const stdin, const stdout, const stderr = if (self.pseudo_console) |pseudo_console| b: {
|
||||||
|
var attribute_list_size: usize = undefined;
|
||||||
|
_ = windows.exp.kernel32.InitializeProcThreadAttributeList(
|
||||||
null,
|
null,
|
||||||
null,
|
1,
|
||||||
windows.TRUE,
|
0,
|
||||||
flags,
|
&attribute_list_size,
|
||||||
if (env_w) |w| w.ptr else null,
|
);
|
||||||
if (cwd_w) |w| w.ptr else null,
|
|
||||||
@ptrCast(&startup_info_ex.StartupInfo),
|
const attribute_list_buf = try arena.alloc(u8, attribute_list_size);
|
||||||
&process_information,
|
if (windows.exp.kernel32.InitializeProcThreadAttributeList(
|
||||||
|
attribute_list_buf.ptr,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
&attribute_list_size,
|
||||||
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||||
|
|
||||||
self.pid = process_information.hProcess;
|
if (windows.exp.kernel32.UpdateProcThreadAttribute(
|
||||||
} else {
|
attribute_list_buf.ptr,
|
||||||
// Null-terminate all our arguments
|
0,
|
||||||
const pathZ = try arena.dupeZ(u8, self.path);
|
windows.exp.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||||
const argsZ = try arena.allocSentinel(?[*:0]u8, self.args.len, null);
|
pseudo_console,
|
||||||
for (self.args, 0..) |arg, i| argsZ[i] = (try arena.dupeZ(u8, arg)).ptr;
|
@sizeOf(windows.exp.HPCON),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||||
|
|
||||||
// Determine our env vars
|
break :b .{ attribute_list_buf.ptr, null, null, null };
|
||||||
const envp = if (self.env) |env_map|
|
} else b: {
|
||||||
(try createNullDelimitedEnvMap(arena, env_map)).ptr
|
const stdin = if (self.stdin) |f| f.handle else null_fd.?;
|
||||||
else if (builtin.link_libc)
|
const stdout = if (self.stdout) |f| f.handle else null_fd.?;
|
||||||
std.c.environ
|
const stderr = if (self.stderr) |f| f.handle else null_fd.?;
|
||||||
else
|
break :b .{ null, stdin, stdout, stderr };
|
||||||
@compileError("missing env vars");
|
};
|
||||||
|
|
||||||
// Fork
|
var startup_info_ex = windows.exp.STARTUPINFOEX{
|
||||||
const pid = try std.os.fork();
|
.StartupInfo = .{
|
||||||
if (pid != 0) {
|
.cb = if (attribute_list != null) @sizeOf(windows.exp.STARTUPINFOEX) else @sizeOf(windows.STARTUPINFOW),
|
||||||
// Parent, return immediately.
|
.hStdError = stderr,
|
||||||
self.pid = @intCast(pid);
|
.hStdOutput = stdout,
|
||||||
return;
|
.hStdInput = stdin,
|
||||||
}
|
.dwFlags = windows.STARTF_USESTDHANDLES,
|
||||||
|
.lpReserved = null,
|
||||||
|
.lpDesktop = null,
|
||||||
|
.lpTitle = null,
|
||||||
|
.dwX = 0,
|
||||||
|
.dwY = 0,
|
||||||
|
.dwXSize = 0,
|
||||||
|
.dwYSize = 0,
|
||||||
|
.dwXCountChars = 0,
|
||||||
|
.dwYCountChars = 0,
|
||||||
|
.dwFillAttribute = 0,
|
||||||
|
.wShowWindow = 0,
|
||||||
|
.cbReserved2 = 0,
|
||||||
|
.lpReserved2 = null,
|
||||||
|
},
|
||||||
|
.lpAttributeList = attribute_list,
|
||||||
|
};
|
||||||
|
|
||||||
// We are the child.
|
var flags: windows.DWORD = windows.exp.CREATE_UNICODE_ENVIRONMENT;
|
||||||
|
if (attribute_list != null) flags |= windows.exp.EXTENDED_STARTUPINFO_PRESENT;
|
||||||
|
|
||||||
// Setup our file descriptors for std streams.
|
var process_information: windows.PROCESS_INFORMATION = undefined;
|
||||||
if (self.stdin) |f| try setupFd(f.handle, os.STDIN_FILENO);
|
if (windows.exp.kernel32.CreateProcessW(
|
||||||
if (self.stdout) |f| try setupFd(f.handle, os.STDOUT_FILENO);
|
application_w.ptr,
|
||||||
if (self.stderr) |f| try setupFd(f.handle, os.STDERR_FILENO);
|
if (command_line_w) |w| w.ptr else null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
windows.TRUE,
|
||||||
|
flags,
|
||||||
|
if (env_w) |w| w.ptr else null,
|
||||||
|
if (cwd_w) |w| w.ptr else null,
|
||||||
|
@ptrCast(&startup_info_ex.StartupInfo),
|
||||||
|
&process_information,
|
||||||
|
) == 0) return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||||
|
|
||||||
// Setup our working directory
|
self.pid = process_information.hProcess;
|
||||||
if (self.cwd) |cwd| try os.chdir(cwd);
|
|
||||||
|
|
||||||
// If the user requested a pre exec callback, call it now.
|
|
||||||
if (self.pre_exec) |f| f(self);
|
|
||||||
|
|
||||||
// Finally, replace our process.
|
|
||||||
_ = std.os.execveZ(pathZ, argsZ, envp) catch null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setupFd(src: File.Handle, target: i32) !void {
|
fn setupFd(src: File.Handle, target: i32) !void {
|
||||||
|
Reference in New Issue
Block a user