core: add function to get process info from the surface

This adds a function to the core surface to get process information
about the process(es) running in the terminal. Currently supported is
the PID of the foreground process and the name of the slave PTY.

If there is an error retrieving the information, or the platform does
not support retieving that information `null` is returned.

This will be useful in exposing the foreground PID and slave PTY name to
AppleScript or other APIs.
This commit is contained in:
Jeffrey C. Ollie
2026-03-18 16:36:18 -05:00
parent 1f89ce91d9
commit 89ae0ea6ef
9 changed files with 327 additions and 30 deletions

View File

@@ -1226,6 +1226,32 @@ const Subprocess = struct {
fn killCommandFlatpak(command: *FlatpakHostCommand) !void {
try command.signal(c.SIGHUP, true);
}
pub const ProcessInfo = enum {
/// The PID of the process that currently controls the PTY.
foreground_pid,
/// Gets the name of the slave PTY. Returned name points to an internal
/// buffer so it should not be modified or freed.
tty_name,
pub fn Type(comptime info: Subprocess.ProcessInfo) type {
return switch (info) {
.foreground_pid => u64,
.tty_name => [:0]const u8,
};
}
};
/// Get information about the process(es) running within the subprocess.
/// Returns `null` if there was an error getting the information or the
/// information is not available on a particular platform.
pub fn getProcessInfo(self: *Subprocess, comptime info: Subprocess.ProcessInfo) ?Subprocess.ProcessInfo.Type(info) {
const pty = &(self.pty orelse return null);
return switch (info) {
.foreground_pid => pty.getProcessInfo(.foreground_pid),
.tty_name => pty.getProcessInfo(.tty_name),
};
}
};
/// The read thread sits in a loop doing the following pseudo code:
@@ -1580,6 +1606,31 @@ fn execCommand(
};
}
pub const ProcessInfo = enum {
/// The PID of the process that currently controls the PTY.
foreground_pid,
/// Gets the name of the slave PTY. Returned name points to an internal
/// buffer so it should not be modified or freed.
tty_name,
pub fn Type(comptime info: ProcessInfo) type {
return switch (info) {
.foreground_pid => u64,
.tty_name => [:0]const u8,
};
}
};
/// Get information about the process(es) running within the backend. Returns
/// `null` if there was an error getting the information or the information is
/// not available on a particular platform.
pub fn getProcessInfo(self: *Exec, comptime info: ProcessInfo) ?ProcessInfo.Type(info) {
return switch (info) {
.foreground_pid => self.subprocess.getProcessInfo(.foreground_pid),
.tty_name => self.subprocess.getProcessInfo(.tty_name),
};
}
test "execCommand darwin: shell command" {
if (comptime !builtin.os.tag.isDarwin()) return error.SkipZigTest;

View File

@@ -764,3 +764,28 @@ pub const ThreadData = struct {
self.* = undefined;
}
};
pub const ProcessInfo = enum {
/// The PID of the process that currently controls the PTY.
foreground_pid,
/// Gets the name of the slave PTY. Returned name points to an internal
/// buffer so it should not be modified or freed.
tty_name,
pub fn Type(comptime info: ProcessInfo) type {
return switch (info) {
.foreground_pid => u64,
.tty_name => [:0]const u8,
};
}
};
/// Get information about the process(es) attached to the backend. Returns
/// `null` if there was an error getting the information or the information is
/// not available on a particular platform.
pub fn getProcessInfo(self: *Termio, comptime info: ProcessInfo) ?ProcessInfo.Type(info) {
return switch (info) {
.foreground_pid => self.backend.getProcessInfo(.foreground_pid),
.tty_name => self.backend.getProcessInfo(.tty_name),
};
}

View File

@@ -100,6 +100,33 @@ pub const Backend = union(Kind) {
),
}
}
pub const ProcessInfo = enum {
/// The PID of the process that currently controls the PTY.
foreground_pid,
/// Gets the name of the slave PTY. Returned name points to an internal
/// buffer so it should not be modified or freed.
tty_name,
pub fn Type(comptime info: ProcessInfo) type {
return switch (info) {
.foreground_pid => u64,
.tty_name => [:0]const u8,
};
}
};
/// Get information about the process(es) attached to the backend. Returns
/// `null` if there was an error getting the information or the information
/// is not available on a particular platform.
pub fn getProcessInfo(self: *Backend, comptime info: ProcessInfo) ?ProcessInfo.Type(info) {
return switch (self.*) {
.exec => |*exec| switch (info) {
.foreground_pid => exec.getProcessInfo(.foreground_pid),
.tty_name => exec.getProcessInfo(.tty_name),
},
};
}
};
/// Termio thread data. See termio.ThreadData for docs.