mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-17 13:02:42 +00:00
OSC 9: Finish parsing all ConEmu OSCs
Adds support for parsing OSC 9;7, 9;8, 9;9, 9;10, 9;11, 9;12
This commit is contained in:
@@ -193,6 +193,28 @@ pub const Command = union(Key) {
|
||||
/// ConEmu GUI macro (OSC 9;6)
|
||||
conemu_guimacro: [:0]const u8,
|
||||
|
||||
/// ConEmu run process (OSC 9;7)
|
||||
conemu_run_process: [:0]const u8,
|
||||
|
||||
/// ConEmu output environment variable (OSC 9;8)
|
||||
conemu_output_environment_variable: [:0]const u8,
|
||||
|
||||
/// ConEmu XTerm keyboard and output emulation (OSC 9;10)
|
||||
/// https://conemu.github.io/en/TerminalModes.html
|
||||
conemu_xterm_emulation: struct {
|
||||
/// null => do not change
|
||||
/// false => turn off
|
||||
/// true => turn on
|
||||
keyboard: ?bool,
|
||||
/// null => do not change
|
||||
/// false => turn off
|
||||
/// true => turn on
|
||||
output: ?bool,
|
||||
},
|
||||
|
||||
/// ConEmu comment (OSC 9;11)
|
||||
conemu_comment: [:0]const u8,
|
||||
|
||||
/// Kitty text sizing protocol (OSC 66)
|
||||
kitty_text_sizing: parsers.kitty_text_sizing.OSC,
|
||||
|
||||
@@ -221,6 +243,10 @@ pub const Command = union(Key) {
|
||||
"conemu_progress_report",
|
||||
"conemu_wait_input",
|
||||
"conemu_guimacro",
|
||||
"conemu_run_process",
|
||||
"conemu_output_environment_variable",
|
||||
"conemu_xterm_emulation",
|
||||
"conemu_comment",
|
||||
"kitty_text_sizing",
|
||||
},
|
||||
);
|
||||
@@ -424,11 +450,15 @@ pub const Parser = struct {
|
||||
.clipboard_contents,
|
||||
.color_operation,
|
||||
.conemu_change_tab_title,
|
||||
.conemu_comment,
|
||||
.conemu_guimacro,
|
||||
.conemu_output_environment_variable,
|
||||
.conemu_progress_report,
|
||||
.conemu_run_process,
|
||||
.conemu_show_message_box,
|
||||
.conemu_sleep,
|
||||
.conemu_wait_input,
|
||||
.conemu_xterm_emulation,
|
||||
.end_of_command,
|
||||
.end_of_input,
|
||||
.hyperlink_end,
|
||||
|
||||
@@ -16,11 +16,11 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
var data = writer.buffered();
|
||||
if (data.len == 0) break :conemu;
|
||||
switch (data[0]) {
|
||||
// Check for OSC 9;1 9;10 9;12
|
||||
// Check for OSC 9;1 9;10 9;11 9;12
|
||||
'1' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
switch (data[1]) {
|
||||
// OSC 9;1
|
||||
// OSC 9;1 sleep
|
||||
';' => {
|
||||
parser.command = .{
|
||||
.conemu_sleep = .{
|
||||
@@ -29,12 +29,74 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;10
|
||||
// OSC 9;10 xterm keyboard and output emulation
|
||||
'0' => {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
if (data.len == 2) {
|
||||
parser.command = .{
|
||||
.conemu_xterm_emulation = .{
|
||||
.keyboard = true,
|
||||
.output = true,
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
}
|
||||
if (data.len < 4) break :conemu;
|
||||
if (data[2] != ';') break :conemu;
|
||||
switch (data[3]) {
|
||||
'0' => {
|
||||
parser.command = .{
|
||||
.conemu_xterm_emulation = .{
|
||||
.keyboard = false,
|
||||
.output = false,
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
'1' => {
|
||||
parser.command = .{
|
||||
.conemu_xterm_emulation = .{
|
||||
.keyboard = true,
|
||||
.output = true,
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
'2' => {
|
||||
parser.command = .{
|
||||
.conemu_xterm_emulation = .{
|
||||
.keyboard = null,
|
||||
.output = false,
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
'3' => {
|
||||
parser.command = .{
|
||||
.conemu_xterm_emulation = .{
|
||||
.keyboard = null,
|
||||
.output = true,
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
else => break :conemu,
|
||||
}
|
||||
},
|
||||
// OSC 9;12
|
||||
// OSC 9;11 comment
|
||||
'1' => {
|
||||
if (data.len < 3) break :conemu;
|
||||
if (data[2] != ';') break :conemu;
|
||||
writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
parser.command = .{
|
||||
.conemu_comment = data[3 .. data.len - 1 :0],
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;12 mark prompt start
|
||||
'2' => {
|
||||
parser.command = .{
|
||||
.prompt_start = .{},
|
||||
@@ -44,7 +106,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
else => break :conemu,
|
||||
}
|
||||
},
|
||||
// OSC 9;2
|
||||
// OSC 9;2 show message box
|
||||
'2' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
@@ -58,7 +120,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;3
|
||||
// OSC 9;3 change tab title
|
||||
'3' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
@@ -80,7 +142,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;4
|
||||
// OSC 9;4 progress report
|
||||
'4' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
@@ -141,12 +203,12 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
}
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;5
|
||||
// OSC 9;5 wait for input
|
||||
'5' => {
|
||||
parser.command = .conemu_wait_input;
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;6
|
||||
// OSC 9;6 guimacro
|
||||
'6' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
@@ -160,26 +222,49 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;7
|
||||
// OSC 9;7 run process
|
||||
'7' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
parser.command = .{
|
||||
.conemu_run_process = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;8
|
||||
// OSC 9;8 output environment variable
|
||||
'8' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
parser.command = .{
|
||||
.conemu_output_environment_variable = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
// OSC 9;9
|
||||
// OSC 9;9 current working directory
|
||||
'9' => {
|
||||
if (data.len < 2) break :conemu;
|
||||
if (data[1] != ';') break :conemu;
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
parser.command = .{
|
||||
.report_pwd = .{
|
||||
.value = data[2 .. data.len - 1 :0],
|
||||
},
|
||||
};
|
||||
return &parser.command;
|
||||
},
|
||||
else => break :conemu,
|
||||
}
|
||||
@@ -764,3 +849,294 @@ test "OSC: 9;6: ConEmu guimacro 3 incomplete -> desktop notification" {
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("6", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;7: ConEmu run process 1" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;7;ab";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_run_process);
|
||||
try testing.expectEqualStrings("ab", cmd.conemu_run_process);
|
||||
}
|
||||
|
||||
test "OSC: 9;7: ConEmu run process 2" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;7;";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_run_process);
|
||||
try testing.expectEqualStrings("", cmd.conemu_run_process);
|
||||
}
|
||||
|
||||
test "OSC: 9;7: ConEmu run process incomplete -> desktop notification" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;7";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("7", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;8: ConEmu output environment variable 1" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;8;ab";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_output_environment_variable);
|
||||
try testing.expectEqualStrings("ab", cmd.conemu_output_environment_variable);
|
||||
}
|
||||
|
||||
test "OSC: 9;8: ConEmu output environment variable 2" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;8;";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_output_environment_variable);
|
||||
try testing.expectEqualStrings("", cmd.conemu_output_environment_variable);
|
||||
}
|
||||
|
||||
test "OSC: 9;8: ConEmu output environment variable incomplete -> desktop notification" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;8";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("8", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;9: ConEmu set current working directory" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;9;ab";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .report_pwd);
|
||||
try testing.expectEqualStrings("ab", cmd.report_pwd.value);
|
||||
}
|
||||
|
||||
test "OSC: 9;9: ConEmu set current working directory incomplete -> desktop notification" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;9";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("9", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 1" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_xterm_emulation);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard.? == true);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output.? == true);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 2" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;0";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_xterm_emulation);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard.? == false);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output.? == false);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 3" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;1";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_xterm_emulation);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard.? == true);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output.? == true);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 4" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;2";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_xterm_emulation);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard == null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output.? == false);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 5" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;3";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_xterm_emulation);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.keyboard == null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output != null);
|
||||
try testing.expect(cmd.conemu_xterm_emulation.output.? == true);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 6" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;4";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("10;4", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 7" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("10;", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;10: ConEmu xterm keyboard and output emulation 8" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;10;abc";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("10;abc", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;11: ConEmu comment" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;11;ab";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .conemu_comment);
|
||||
try testing.expectEqualStrings("ab", cmd.conemu_comment);
|
||||
}
|
||||
|
||||
test "OSC: 9;11: ConEmu comment incomplete -> desktop notification" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;11";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .show_desktop_notification);
|
||||
try testing.expectEqualStrings("11", cmd.show_desktop_notification.body);
|
||||
}
|
||||
|
||||
test "OSC: 9;12: ConEmu mark prompt start 1" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;12";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .prompt_start);
|
||||
}
|
||||
|
||||
test "OSC: 9;12: ConEmu mark prompt start 2" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(testing.allocator);
|
||||
defer p.deinit();
|
||||
|
||||
const input = "9;12;abc";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end('\x1b').?.*;
|
||||
try testing.expect(cmd == .prompt_start);
|
||||
}
|
||||
|
||||
@@ -2107,6 +2107,10 @@ pub fn Stream(comptime Handler: type) type {
|
||||
.conemu_change_tab_title,
|
||||
.conemu_wait_input,
|
||||
.conemu_guimacro,
|
||||
.conemu_comment,
|
||||
.conemu_xterm_emulation,
|
||||
.conemu_output_environment_variable,
|
||||
.conemu_run_process,
|
||||
.kitty_text_sizing,
|
||||
=> {
|
||||
log.debug("unimplemented OSC callback: {}", .{cmd});
|
||||
|
||||
Reference in New Issue
Block a user