terminal: OSC7 with empty URL resets the pwd to nil

When an empty string is given to OSC7, the pwd is reset to nil (as if
the terminal never received a pwd report to begin with). This is
analogous to how OSC0/2 reset the title to nil when given an empty
string.

This is practically useful for macOS because it allows our proxy icon to
also be reset instead of being stuck on the last known path.

This breaks from any known terminal behavior. As far as I can find, this
is totally unspecified so we're somewhat free to do what we want. I
don't think any terminal programs depend on this behavior, so I think
it's safe to change it.
This commit is contained in:
Mitchell Hashimoto
2024-11-13 13:35:51 -08:00
parent edfef1c8df
commit e225eb9eff
2 changed files with 36 additions and 12 deletions

View File

@ -641,7 +641,7 @@ pub const Parser = struct {
.@"7" => switch (c) {
';' => {
self.command = .{ .report_pwd = .{ .value = "" } };
self.complete = true;
self.state = .string;
self.temp_state = .{ .str = &self.command.report_pwd.value };
self.buf_start = self.buf_idx;
@ -1382,6 +1382,18 @@ test "OSC: report pwd" {
try testing.expect(std.mem.eql(u8, "file:///tmp/example", cmd.report_pwd.value));
}
test "OSC: report pwd empty" {
const testing = std.testing;
var p: Parser = .{};
const input = "7;";
for (input) |ch| p.next(ch);
const cmd = p.end(null).?;
try testing.expect(cmd == .report_pwd);
try testing.expect(std.mem.eql(u8, "", cmd.report_pwd.value));
}
test "OSC: pointer cursor" {
const testing = std.testing;
@ -1395,17 +1407,6 @@ test "OSC: pointer cursor" {
try testing.expect(std.mem.eql(u8, "pointer", cmd.mouse_shape.value));
}
test "OSC: report pwd empty" {
const testing = std.testing;
var p: Parser = .{};
const input = "7;";
for (input) |ch| p.next(ch);
try testing.expect(p.end(null) == null);
}
test "OSC: longer than buffer" {
const testing = std.testing;

View File

@ -1,5 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const xev = @import("xev");
const apprt = @import("../apprt.zig");
@ -1048,6 +1049,28 @@ pub const StreamHandler = struct {
}
pub fn reportPwd(self: *StreamHandler, url: []const u8) !void {
// Special handling for the empty URL. We treat the empty URL
// as resetting the pwd as if we never saw a pwd. I can't find any
// other terminal that does this but it seems like a reasonable
// behavior that enables some useful features. For example, the macOS
// proxy icon can be hidden when a program reports it doesn't know
// the pwd rather than showing a stale pwd.
if (url.len == 0) {
// Blank value can never fail because no allocs happen.
self.terminal.setPwd("") catch unreachable;
// If we haven't seen a title, we're using the pwd as our title.
// Set it to blank which will reset our title behavior.
if (!self.seen_title) {
try self.changeWindowTitle("");
assert(!self.seen_title);
}
// Report the change.
self.surfaceMessageWriter(.{ .pwd_change = .{ .stable = "" } });
return;
}
if (builtin.os.tag == .windows) {
log.warn("reportPwd unimplemented on windows", .{});
return;