Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,8 @@ ghostty_surface_config_s ghostty_surface_inherited_config(ghostty_surface_t, gho
void ghostty_surface_update_config(ghostty_surface_t, ghostty_config_t);
bool ghostty_surface_needs_confirm_quit(ghostty_surface_t);
bool ghostty_surface_process_exited(ghostty_surface_t);
uint64_t ghostty_surface_child_pid(ghostty_surface_t);
const char* ghostty_surface_tty_name(ghostty_surface_t);
void ghostty_surface_refresh(ghostty_surface_t);
void ghostty_surface_draw(ghostty_surface_t);
void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ struct TerminalEntity: AppEntity {
@Property(title: "Kind")
var kind: Kind

@Property(title: "PID")
var pid: Int?

@Property(title: "TTY")
var tty: String?

var screenshot: NSImage?

static var typeDisplayRepresentation: TypeDisplayRepresentation {
Expand Down Expand Up @@ -49,6 +55,8 @@ struct TerminalEntity: AppEntity {
self.id = view.id
self.title = view.title
self.workingDirectory = view.pwd
self.pid = view.surfaceModel?.childPID
self.tty = view.surfaceModel?.ttyName
if let nsImage = ImageRenderer(content: view.screenshot()).nsImage {
self.screenshot = nsImage
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ struct GetTerminalDetailsIntent: AppIntent {
switch detail {
case .title: return .result(value: terminal.title)
case .workingDirectory: return .result(value: terminal.workingDirectory)
case .pid: return .result(value: terminal.pid.map { String($0) })
case .tty: return .result(value: terminal.tty)
case .allContents:
guard let view = terminal.surfaceView else { throw GhosttyIntentError.surfaceNotFound }
return .result(value: view.cachedScreenContents.get())
Expand All @@ -53,6 +55,8 @@ struct GetTerminalDetailsIntent: AppIntent {
enum TerminalDetail: String {
case title
case workingDirectory
case pid
case tty
case allContents
case selectedText
case visibleText
Expand All @@ -64,6 +68,8 @@ extension TerminalDetail: AppEnum {
static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [
.title: .init(title: "Title"),
.workingDirectory: .init(title: "Working Directory"),
.pid: .init(title: "PID"),
.tty: .init(title: "TTY"),
.allContents: .init(title: "Full Contents"),
.selectedText: .init(title: "Selected Text"),
.visibleText: .init(title: "Visible Text"),
Expand Down
14 changes: 14 additions & 0 deletions macos/Sources/Ghostty/Ghostty.Surface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ extension Ghostty {
event.withCValue { keyIsBinding($0) }
}

/// The PID of the foreground process, or nil if not available.
@MainActor
var childPID: Int? {
let pid = ghostty_surface_child_pid(surface)
return pid != 0 ? Int(pid) : nil
}

/// The TTY device name (e.g. "/dev/ttys003"), or nil if not available.
@MainActor
var ttyName: String? {
guard let ptr = ghostty_surface_tty_name(surface) else { return nil }
return String(cString: ptr)
}

/// Whether the terminal has captured mouse input.
///
/// When the mouse is captured, the terminal application is receiving mouse events
Expand Down
13 changes: 13 additions & 0 deletions src/apprt/embedded.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,19 @@ pub const CAPI = struct {
return surface.core_surface.child_exited;
}

/// Returns the PID of the foreground process running in the surface,
/// or 0 if the process is not available.
export fn ghostty_surface_child_pid(surface: *Surface) u64 {
return surface.core_surface.getProcessInfo(.foreground_pid) orelse 0;
}

/// Returns the TTY device name of the surface (e.g. "/dev/ttys003"),
/// or null if not available.
export fn ghostty_surface_tty_name(surface: *Surface) ?[*:0]const u8 {
const name = surface.core_surface.getProcessInfo(.tty_name) orelse return null;
return name.ptr;
}

/// Returns true if the surface has a selection.
export fn ghostty_surface_has_selection(surface: *Surface) bool {
return surface.core_surface.hasSelection();
Expand Down