termio: handle empty titles (OSC 0/2)

Fixes #2651

First, our OSC parser didn't allow blank OSC 0 or 2 requests. This
should be allowed and this fixes that with a test.

Second, it seems many terminals (iTerm2, Kitty) treat setting a blank
title as resetting to whatever the default title is rather than
explicitly setting it as blank. If a program wants a title to be blank
they should send a single space. This commit follows this behavior.
This commit is contained in:
Mitchell Hashimoto
2024-11-13 12:10:21 -08:00
parent 523e3a6ae3
commit 067a36d67c
2 changed files with 30 additions and 3 deletions

View File

@ -400,7 +400,7 @@ pub const Parser = struct {
.@"0" => switch (c) {
';' => {
self.command = .{ .change_window_title = undefined };
self.complete = true;
self.state = .string;
self.temp_state = .{ .str = &self.command.change_window_title };
self.buf_start = self.buf_idx;
@ -477,7 +477,7 @@ pub const Parser = struct {
'2' => self.state = .@"22",
';' => {
self.command = .{ .change_window_title = undefined };
self.complete = true;
self.state = .string;
self.temp_state = .{ .str = &self.command.change_window_title };
self.buf_start = self.buf_idx;
@ -1159,6 +1159,17 @@ test "OSC: change_window_title with utf8" {
try testing.expectEqualStrings("", cmd.change_window_title);
}
test "OSC: change_window_title empty" {
const testing = std.testing;
var p: Parser = .{};
p.next('2');
p.next(';');
const cmd = p.end(null).?;
try testing.expect(cmd == .change_window_title);
try testing.expectEqualStrings("", cmd.change_window_title);
}
test "OSC: change_window_icon" {
const testing = std.testing;

View File

@ -965,7 +965,23 @@ pub const StreamHandler = struct {
@memcpy(buf[0..title.len], title);
buf[title.len] = 0;
// Mark that we've seen a title
// Special handling for the empty title. We treat the empty title
// as resetting to as if we never saw a title. Other terminals
// behave this way too (e.g. iTerm2).
if (title.len == 0) {
// If we have a pwd then we set the title as the pwd else
// we just set it to blank.
if (self.terminal.getPwd()) |pwd| pwd: {
if (pwd.len >= buf.len) break :pwd;
@memcpy(buf[0..pwd.len], pwd);
buf[pwd.len] = 0;
}
self.surfaceMessageWriter(.{ .set_title = buf });
self.seen_title = false;
return;
}
self.seen_title = true;
self.surfaceMessageWriter(.{ .set_title = buf });
}