From f047db6a3be5d0bbc5a9154ea8fa0d77743222e8 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Tue, 26 Aug 2025 16:28:25 -0500 Subject: [PATCH] osc: parse OSC 9;6 gui macros --- src/terminal/osc.zig | 72 +++++++++++++++++++++++++++++++++++++++++ src/terminal/stream.zig | 7 +++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/terminal/osc.zig b/src/terminal/osc.zig index 808cfc08f..6cf76e92e 100644 --- a/src/terminal/osc.zig +++ b/src/terminal/osc.zig @@ -167,6 +167,9 @@ pub const Command = union(enum) { /// Wait input (OSC 9;5) wait_input: void, + /// ConEmu GUI macro (OSC 9;6) + conemu_guimacro: []const u8, + pub const ColorOperation = union(enum) { pub const Source = enum(u16) { // these numbers are based on the OSC operation code @@ -431,6 +434,7 @@ pub const Parser = struct { conemu_progress_state, conemu_progress_prevalue, conemu_progress_value, + conemu_guimacro, }; pub fn init() Parser { @@ -972,6 +976,13 @@ pub const Parser = struct { self.command = .{ .wait_input = {} }; self.complete = true; }, + '6' => { + self.state = .conemu_guimacro; + // This will end up being either a ConEmu GUI macro OSC 9;6, + // or a desktop notification OSC 9 that begins with '6', so + // mark as complete. + self.complete = true; + }, // Todo: parse out other ConEmu operating system commands. // Even if we don't support them we probably don't want @@ -1104,6 +1115,19 @@ pub const Parser = struct { }, }, + .conemu_guimacro => switch (c) { + ';' => { + self.command = .{ .conemu_guimacro = undefined }; + self.temp_state = .{ .str = &self.command.conemu_guimacro }; + self.buf_start = self.buf_idx; + self.state = .string; + self.complete = true; + }, + // OSC 9;6 is a desktop + // notification. + else => self.showDesktopNotification(), + }, + .semantic_prompt => switch (c) { 'A' => { self.state = .semantic_option_start; @@ -1600,6 +1624,12 @@ pub const Parser = struct { .hyperlink_uri => self.endHyperlink(), .string => self.endString(), .conemu_sleep_value => self.endConEmuSleepValue(), + .conemu_guimacro => { + // We received OSC 9;6 ST, but nothing else, finish off as a + // desktop notification with "6" as the body. + self.showDesktopNotification(); + self.endString(); + }, .allocable_string => self.endAllocableString(), .kitty_color_protocol_key => self.endKittyColorProtocolOption(.key_only, true), .kitty_color_protocol_value => self.endKittyColorProtocolOption(.key_and_value, true), @@ -3434,3 +3464,45 @@ test "OSC: kitty color protocol no key" { try testing.expect(cmd == .kitty_color_protocol); try testing.expectEqual(0, cmd.kitty_color_protocol.list.items.len); } + +test "OSC: 9;6: ConEmu guimacro 1" { + const testing = std.testing; + + var p: Parser = .initAlloc(testing.allocator); + defer p.deinit(); + + const input = "9;6;a"; + for (input) |ch| p.next(ch); + + const cmd = p.end('\x1b').?; + try testing.expect(cmd == .conemu_guimacro); + try testing.expectEqualStrings("a", cmd.conemu_guimacro); +} + +test "OSC: 9;6: ConEmu guimacro 2" { + const testing = std.testing; + + var p: Parser = .initAlloc(testing.allocator); + defer p.deinit(); + + const input = "9;6;ab"; + for (input) |ch| p.next(ch); + + const cmd = p.end('\x1b').?; + try testing.expect(cmd == .conemu_guimacro); + try testing.expectEqualStrings("ab", cmd.conemu_guimacro); +} + +test "OSC: 9;6: ConEmu guimacro 3 incomplete -> desktop notification" { + const testing = std.testing; + + var p: Parser = .initAlloc(testing.allocator); + defer p.deinit(); + + const input = "9;6"; + for (input) |ch| p.next(ch); + + const cmd = p.end('\x1b').?; + try testing.expect(cmd == .show_desktop_notification); + try testing.expectEqualStrings("6", cmd.show_desktop_notification.body); +} diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index f40fc4c94..cac1da2f5 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -1605,7 +1605,12 @@ pub fn Stream(comptime Handler: type) type { } else log.warn("unimplemented OSC callback: {}", .{cmd}); }, - .sleep, .show_message_box, .change_conemu_tab_title, .wait_input => { + .sleep, + .show_message_box, + .change_conemu_tab_title, + .wait_input, + .conemu_guimacro, + => { log.warn("unimplemented OSC callback: {}", .{cmd}); },