From 7ae94e145d4da3eb4c4e1d92c62b966ae0652599 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 6 Jan 2025 15:39:21 -0800 Subject: [PATCH] terminal: ConEmu OSC9 parsing is more robust and correct Related to #4485 This commit matches ConEmu's parsing logic[^1] more faithfully. For any substate that requires a progress, ConEmu parses so long as there is a number and then just ignores the rest. For substates that don't require a progress, ConEmu literally ignores everything after the state. Tests cover both. [^1]: https://github.com/Maximus5/ConEmu/blob/740b09c363cb16fbb730d72c53eaca1c530a016e/src/ConEmuCD/ConAnsiImpl.cpp#L2264 --- src/terminal/osc.zig | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index e9ab5e1e3..33d753c9f 100644 --- a/src/terminal/osc.zig +++ b/src/terminal/osc.zig @@ -274,6 +274,7 @@ pub const Parser = struct { pub const State = enum { empty, invalid, + swallow, // Command prefixes. We could just accumulate and compare (mem.eql) // but the state space is small enough that we just build it up this way. @@ -451,6 +452,8 @@ pub const Parser = struct { else => self.state = .invalid, }, + .swallow => {}, + .@"0" => switch (c) { ';' => { self.command = .{ .change_window_title = undefined }; @@ -822,7 +825,7 @@ pub const Parser = struct { self.buf_start = self.buf_idx; self.complete = true; self.state = .conemu_sleep_value; - }, + }, else => self.state = .invalid, }, @@ -871,7 +874,7 @@ pub const Parser = struct { .conemu_progress_state => switch (c) { '0' => { self.command.progress.state = .remove; - self.state = .conemu_progress_prevalue; + self.state = .swallow; self.complete = true; }, '1' => { @@ -887,7 +890,7 @@ pub const Parser = struct { '3' => { self.command.progress.state = .indeterminate; self.complete = true; - self.state = .conemu_progress_prevalue; + self.state = .swallow; }, '4' => { self.command.progress.state = .pause; @@ -934,7 +937,10 @@ pub const Parser = struct { } }, - else => self.showDesktopNotification(), + else => { + self.state = .swallow; + self.complete = true; + }, }, .query_fg_color => switch (c) { @@ -1965,18 +1971,18 @@ test "OSC: OSC9 progress set double digit" { try testing.expect(cmd.progress.progress == 94); } -test "OSC: OSC9 progress set extra semicolon triggers desktop notification" { +test "OSC: OSC9 progress set extra semicolon ignored" { const testing = std.testing; var p: Parser = .{}; - const input = "9;4;1;100;"; + const input = "9;4;1;100"; for (input) |ch| p.next(ch); const cmd = p.end('\x1b').?; - try testing.expect(cmd == .show_desktop_notification); - try testing.expectEqualStrings(cmd.show_desktop_notification.title, ""); - try testing.expectEqualStrings(cmd.show_desktop_notification.body, "4;1;100;"); + try testing.expect(cmd == .progress); + try testing.expect(cmd.progress.state == .set); + try testing.expect(cmd.progress.progress == 100); } test "OSC: OSC9 progress remove with no progress" { @@ -1993,6 +1999,20 @@ test "OSC: OSC9 progress remove with no progress" { try testing.expect(cmd.progress.progress == null); } +test "OSC: OSC9 progress remove with double semicolon" { + const testing = std.testing; + + var p: Parser = .{}; + + const input = "9;4;0;;"; + for (input) |ch| p.next(ch); + + const cmd = p.end('\x1b').?; + try testing.expect(cmd == .progress); + try testing.expect(cmd.progress.state == .remove); + try testing.expect(cmd.progress.progress == null); +} + test "OSC: OSC9 progress remove ignores progress" { const testing = std.testing; @@ -2016,9 +2036,8 @@ test "OSC: OSC9 progress remove extra semicolon" { for (input) |ch| p.next(ch); const cmd = p.end('\x1b').?; - try testing.expect(cmd == .show_desktop_notification); - try testing.expectEqualStrings(cmd.show_desktop_notification.title, ""); - try testing.expectEqualStrings(cmd.show_desktop_notification.body, "4;0;100;"); + try testing.expect(cmd == .progress); + try testing.expect(cmd.progress.state == .remove); } test "OSC: OSC9 progress error" {