terminal: store title set by escape sequences

Add a title field to Terminal, mirroring the existing pwd field.
The title is set via setTitle/getTitle and tracks the most recent
value written by OSC 0/2 sequences. The stream handler now persists
the title in terminal state in addition to forwarding it to the
surface. The field is cleared on full reset.
This commit is contained in:
Mitchell Hashimoto
2026-03-22 20:33:16 -07:00
parent 6366ce9a22
commit 08a44d7e69
2 changed files with 25 additions and 0 deletions

View File

@@ -67,6 +67,9 @@ scrolling_region: ScrollingRegion,
/// The last reported pwd, if any.
pwd: std.ArrayList(u8),
/// The title of the terminal as set by escape sequences (e.g. OSC 0/2).
title: std.ArrayList(u8),
/// The color state for this terminal.
colors: Colors,
@@ -219,6 +222,7 @@ pub fn init(
.right = cols - 1,
},
.pwd = .empty,
.title = .empty,
.colors = opts.colors,
.modes = .{
.values = opts.default_modes,
@@ -231,6 +235,7 @@ pub fn deinit(self: *Terminal, alloc: Allocator) void {
self.tabstops.deinit(alloc);
self.screens.deinit(alloc);
self.pwd.deinit(alloc);
self.title.deinit(alloc);
self.* = undefined;
}
@@ -2881,6 +2886,19 @@ pub fn getPwd(self: *const Terminal) ?[]const u8 {
return self.pwd.items;
}
/// Set the title for the terminal, as set by escape sequences (e.g. OSC 0/2).
pub fn setTitle(self: *Terminal, t: []const u8) !void {
self.title.clearRetainingCapacity();
try self.title.appendSlice(self.gpa(), t);
}
/// Returns the title for the terminal, if any. The memory is owned by the
/// Terminal and is not copied. It is safe until a reset or setTitle.
pub fn getTitle(self: *const Terminal) ?[]const u8 {
if (self.title.items.len == 0) return null;
return self.title.items;
}
/// Switch to the given screen type (alternate or primary).
///
/// This does NOT handle behaviors such as clearing the screen,
@@ -3090,6 +3108,7 @@ pub fn fullReset(self: *Terminal) void {
self.tabstops.reset(TABSTOP_INTERVAL);
self.previous_char = null;
self.pwd.clearRetainingCapacity();
self.title.clearRetainingCapacity();
self.status_display = .main;
self.scrolling_region = .{
.top = 0,

View File

@@ -999,6 +999,12 @@ pub const StreamHandler = struct {
return;
}
// Set the title on the terminal state. We ignore any errors since
// we can continue to operate just fine without it.
self.terminal.setTitle(title) catch |err| {
log.warn("error setting title in terminal state: {e}", .{err});
};
@memcpy(buf[0..title.len], title);
buf[title.len] = 0;