mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 11:35:48 +00:00
terminal/osc: boilerplate new OSC 133 parsing
This commit is contained in:
@@ -41,6 +41,9 @@ pub const Command = union(Key) {
|
||||
/// in the log.
|
||||
change_window_icon: [:0]const u8,
|
||||
|
||||
/// Semantic prompt command: https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md
|
||||
semantic_prompt: parsers.semantic_prompt2.Command,
|
||||
|
||||
/// First do a fresh-line. Then start a new command, and enter prompt mode:
|
||||
/// Subsequent text (until a OSC "133;B" or OSC "133;I" command) is a
|
||||
/// prompt string (as if followed by OSC 133;P;k=i\007). Note: I've noticed
|
||||
@@ -225,6 +228,7 @@ pub const Command = union(Key) {
|
||||
"invalid",
|
||||
"change_window_title",
|
||||
"change_window_icon",
|
||||
"semantic_prompt",
|
||||
"prompt_start",
|
||||
"prompt_end",
|
||||
"end_of_input",
|
||||
@@ -469,6 +473,7 @@ pub const Parser = struct {
|
||||
.prompt_end,
|
||||
.prompt_start,
|
||||
.report_pwd,
|
||||
.semantic_prompt,
|
||||
.show_desktop_notification,
|
||||
.kitty_text_sizing,
|
||||
=> {},
|
||||
@@ -751,7 +756,7 @@ pub const Parser = struct {
|
||||
|
||||
.@"77" => null,
|
||||
|
||||
.@"133" => parsers.semantic_prompt.parse(self, terminator_ch),
|
||||
.@"133" => parsers.semantic_prompt2.parse(self, terminator_ch),
|
||||
|
||||
.@"777" => parsers.rxvt_extension.parse(self, terminator_ch),
|
||||
|
||||
|
||||
@@ -13,19 +13,8 @@ pub const osc9 = @import("parsers/osc9.zig");
|
||||
pub const report_pwd = @import("parsers/report_pwd.zig");
|
||||
pub const rxvt_extension = @import("parsers/rxvt_extension.zig");
|
||||
pub const semantic_prompt = @import("parsers/semantic_prompt.zig");
|
||||
pub const semantic_prompt2 = @import("parsers/semantic_prompt2.zig");
|
||||
|
||||
test {
|
||||
_ = change_window_icon;
|
||||
_ = change_window_title;
|
||||
_ = clipboard_operation;
|
||||
_ = color;
|
||||
_ = hyperlink;
|
||||
_ = iterm2;
|
||||
_ = kitty_color;
|
||||
_ = kitty_text_sizing;
|
||||
_ = mouse_shape;
|
||||
_ = osc9;
|
||||
_ = report_pwd;
|
||||
_ = rxvt_extension;
|
||||
_ = semantic_prompt;
|
||||
std.testing.refAllDecls(@This());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md
|
||||
const std = @import("std");
|
||||
|
||||
const string_encoding = @import("../../../os/string_encoding.zig");
|
||||
|
||||
const Parser = @import("../../osc.zig").Parser;
|
||||
const Command = @import("../../osc.zig").Command;
|
||||
|
||||
|
||||
92
src/terminal/osc/parsers/semantic_prompt2.zig
Normal file
92
src/terminal/osc/parsers/semantic_prompt2.zig
Normal file
@@ -0,0 +1,92 @@
|
||||
//! https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md
|
||||
const std = @import("std");
|
||||
const Parser = @import("../../osc.zig").Parser;
|
||||
const OSCCommand = @import("../../osc.zig").Command;
|
||||
|
||||
const log = std.log.scoped(.osc_semantic_prompt);
|
||||
|
||||
pub const Command = union(enum) {
|
||||
fresh_line,
|
||||
fresh_line_new_prompt: Options,
|
||||
};
|
||||
|
||||
pub const Options = struct {
|
||||
aid: ?[:0]const u8,
|
||||
cl: ?Click,
|
||||
// TODO: more
|
||||
|
||||
pub const init: Options = .{
|
||||
.aid = null,
|
||||
.click = null,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Click = enum {
|
||||
line,
|
||||
multiple,
|
||||
conservative_vertical,
|
||||
smart_vertical,
|
||||
};
|
||||
|
||||
/// Parse OSC 133, semantic prompts
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*OSCCommand {
|
||||
const writer = parser.writer orelse {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
if (data.len == 0) {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
}
|
||||
|
||||
parser.command = command: {
|
||||
parse: switch (data[0]) {
|
||||
'L' => {
|
||||
if (data.len > 1) break :parse;
|
||||
break :command .{ .semantic_prompt = .fresh_line };
|
||||
},
|
||||
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Any fallthroughs are invalid
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
|
||||
return &parser.command;
|
||||
}
|
||||
|
||||
test "OSC 133: fresh_line" {
|
||||
const testing = std.testing;
|
||||
|
||||
var p: Parser = .init(null);
|
||||
|
||||
const input = "133;L";
|
||||
for (input) |ch| p.next(ch);
|
||||
|
||||
const cmd = p.end(null).?.*;
|
||||
try testing.expect(cmd == .semantic_prompt);
|
||||
try testing.expect(cmd.semantic_prompt == .fresh_line);
|
||||
}
|
||||
|
||||
test "OSC 133: fresh_line extra contents" {
|
||||
const testing = std.testing;
|
||||
|
||||
// Random
|
||||
{
|
||||
var p: Parser = .init(null);
|
||||
const input = "133;Lol";
|
||||
for (input) |ch| p.next(ch);
|
||||
try testing.expect(p.end(null) == null);
|
||||
}
|
||||
|
||||
// Options
|
||||
{
|
||||
var p: Parser = .init(null);
|
||||
const input = "133;L;aid=foo";
|
||||
for (input) |ch| p.next(ch);
|
||||
try testing.expect(p.end(null) == null);
|
||||
}
|
||||
}
|
||||
@@ -2003,6 +2003,9 @@ pub fn Stream(comptime Handler: type) type {
|
||||
// ref: https://github.com/qwerasd205/asciinema-stats
|
||||
|
||||
switch (cmd) {
|
||||
// TODO
|
||||
.semantic_prompt => {},
|
||||
|
||||
.change_window_title => |title| {
|
||||
@branchHint(.likely);
|
||||
if (!std.unicode.utf8ValidateSlice(title)) {
|
||||
|
||||
Reference in New Issue
Block a user