Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ typedef struct {
typedef enum {
GHOSTTY_PROMPT_TITLE_SURFACE,
GHOSTTY_PROMPT_TITLE_TAB,
GHOSTTY_PROMPT_TITLE_WINDOW,
} ghostty_action_prompt_title_e;

// apprt.action.Pwd.C
Expand Down
31 changes: 31 additions & 0 deletions macos/Sources/Features/Terminal/BaseTerminalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,37 @@ class BaseTerminalController: NSWindowController,
}
}

/// Prompt the user to change the window title.
func promptWindowTitle() {
guard let window else { return }

let alert = NSAlert()
alert.messageText = "Change Window Title"
alert.informativeText = "Leave blank to restore the default."
alert.alertStyle = .informational

let textField = NSTextField(frame: NSRect(x: 0, y: 0, width: 250, height: 24))
textField.stringValue = titleOverride ?? window.title
alert.accessoryView = textField

alert.addButton(withTitle: "OK")
alert.addButton(withTitle: "Cancel")

alert.window.initialFirstResponder = textField

alert.beginSheetModal(for: window) { [weak self] response in
guard let self else { return }
guard response == .alertFirstButtonReturn else { return }

let newTitle = textField.stringValue
if newTitle.isEmpty {
self.titleOverride = nil
} else {
self.titleOverride = newTitle
}
}
}

/// Close a surface from a view.
func closeSurface(
_ view: Ghostty.SurfaceView,
Expand Down
3 changes: 3 additions & 0 deletions macos/Sources/Ghostty/Ghostty.Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,14 @@ extension Ghostty.Action {
enum PromptTitle {
case surface
case tab
case window

init(_ c: ghostty_action_prompt_title_e) {
switch c {
case GHOSTTY_PROMPT_TITLE_TAB:
self = .tab
case GHOSTTY_PROMPT_TITLE_WINDOW:
self = .window
default:
self = .surface
}
Expand Down
23 changes: 23 additions & 0 deletions macos/Sources/Ghostty/Ghostty.App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,29 @@ extension Ghostty {
assertionFailure()
return false
}

case .window:
switch (target.tag) {
case GHOSTTY_TARGET_APP:
guard let window = NSApp.mainWindow ?? NSApp.keyWindow,
let controller = window.windowController as? BaseTerminalController
else { return false }
controller.promptWindowTitle()
return true

case GHOSTTY_TARGET_SURFACE:
guard let surface = target.target.surface else { return false }
guard let surfaceView = self.surfaceView(from: surface) else { return false }
guard let window = surfaceView.window,
let controller = window.windowController as? BaseTerminalController
else { return false }
controller.promptWindowTitle()
return true

default:
assertionFailure()
return false
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/Surface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5478,6 +5478,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.tab,
),

.prompt_window_title => return try self.rt_app.performAction(
.{ .surface = self },
.prompt_title,
.window,
),

.clear_screen => {
// This is a duplicate of some of the logic in termio.clearScreen
// but we need to do this here so we can know the answer before
Expand Down
3 changes: 2 additions & 1 deletion src/apprt/action.zig
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,11 @@ pub const MouseVisibility = enum(c_int) {
hidden,
};

/// Whether to prompt for the surface title or tab title.
/// Whether to prompt for the surface title, tab title, or window title.
pub const PromptTitle = enum(c_int) {
surface,
tab,
window,
};

pub const MouseOverLink = struct {
Expand Down
4 changes: 4 additions & 0 deletions src/apprt/gtk/class/application.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,10 @@ const Action = struct {
},
}
},
.window => {
// GTK does not yet support window title prompting
return false;
},
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/input/Binding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ pub const Action = union(enum) {
/// and persists across focus changes within the tab.
prompt_tab_title,

/// Change the title of the current window via a pop-up prompt. The
/// title set via this prompt overrides any title set by the terminal
/// and persists across tab changes within the window.
prompt_window_title,

/// Create a new split in the specified direction.
///
/// Valid arguments:
Expand Down Expand Up @@ -1327,6 +1332,7 @@ pub const Action = union(enum) {
.set_font_size,
.prompt_surface_title,
.prompt_tab_title,
.prompt_window_title,
.clear_screen,
.select_all,
.scroll_to_top,
Expand Down
10 changes: 8 additions & 2 deletions src/input/command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -440,16 +440,22 @@ fn actionCommands(action: Action.Key) []const Command {

.prompt_surface_title => comptime &.{.{
.action = .prompt_surface_title,
.title = "Change Terminal Title...",
.title = "Change Terminal Title\u{2026}",
Comment thread
jcollie marked this conversation as resolved.
Resolved
.description = "Prompt for a new title for the current terminal.",
}},

.prompt_tab_title => comptime &.{.{
.action = .prompt_tab_title,
.title = "Change Tab Title...",
.title = "Change Tab Title\u{2026}",
Comment thread
jcollie marked this conversation as resolved.
Resolved
.description = "Prompt for a new title for the current tab.",
}},

.prompt_window_title => comptime &.{.{
.action = .prompt_window_title,
.title = "Change Window Title\u{2026}",
Comment thread
jcollie marked this conversation as resolved.
Resolved
.description = "Prompt for a new title for the current window.",
}},

.new_split => comptime &.{
.{
.action = .{ .new_split = .left },
Expand Down