diff --git a/macos/Sources/Ghostty/SurfaceView.swift b/macos/Sources/Ghostty/SurfaceView.swift index 25c74b3dc..81a7bca81 100644 --- a/macos/Sources/Ghostty/SurfaceView.swift +++ b/macos/Sources/Ghostty/SurfaceView.swift @@ -123,7 +123,7 @@ extension Ghostty { // The current title of the surface as defined by the pty. This can be // changed with escape codes. This is public because the callbacks go // to the app level and it is set from there. - @Published var title: String = "" + @Published var title: String = "👻" private(set) var surface: ghostty_surface_t? var error: Error? = nil diff --git a/src/shell-integration/zsh/ghostty-integration b/src/shell-integration/zsh/ghostty-integration index 32cddaeb8..3e85d23da 100755 --- a/src/shell-integration/zsh/ghostty-integration +++ b/src/shell-integration/zsh/ghostty-integration @@ -194,6 +194,12 @@ _ghostty_deferred_init() { _ghostty_report_pwd" _ghostty_report_pwd + # Enable terminal title changes. + functions[_ghostty_precmd]+=" + builtin print -rnu $_ghostty_fd \$'\\e]2;'\"\${(%):-%(4~|…/%3~|%~)}\"\$'\\a'" + functions[_ghostty_preexec]+=" + builtin print -rnu $_ghostty_fd \$'\\e]2;'\"\${(V)1}\"\$'\\a'" + # Enable cursor shape changes depending on the current keymap. # This implementation leaks blinking block cursor into external commands # executed from zle. For example, users of fzf-based widgets may find diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 29d716bb8..88881299a 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -400,6 +400,10 @@ const EventData = struct { /// flooding with cursor resets. last_cursor_reset: i64 = 0, + /// This is set to true when we've seen a title escape sequence. We use + /// this to determine if we need to default the window title. + seen_title: bool = false, + pub fn deinit(self: *EventData, alloc: Allocator) void { // Clear our write pools. We know we aren't ever going to do // any more IO since we stop our data stream below so we can just @@ -1377,6 +1381,9 @@ const StreamHandler = struct { std.mem.copy(u8, &buf, title); buf[title.len] = 0; + // Mark that we've seen a title + self.ev.seen_title = true; + _ = self.ev.surface_mailbox.push(.{ .set_title = buf, }, .{ .forever = {} }); @@ -1458,5 +1465,11 @@ const StreamHandler = struct { log.debug("terminal pwd: {s}", .{uri.path}); try self.terminal.setPwd(uri.path); + + // If we haven't seen a title, use our pwd as the title. + if (!self.ev.seen_title) { + try self.changeWindowTitle(uri.path); + self.ev.seen_title = false; + } } };