mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Merge 37f06ca72df9178f7160d3f9ef09b24ff84cf05a into fa6b01c8f52ae14ad4737b21fb34d53d8a657c86
This commit is contained in:
@ -199,18 +199,37 @@ pub const VTEvent = struct {
|
||||
void => {},
|
||||
[]const u8 => try md.put("data", try alloc.dupeZ(u8, v)),
|
||||
else => |T| switch (@typeInfo(T)) {
|
||||
.Struct => |info| inline for (info.fields) |field| {
|
||||
try encodeMetadataSingle(
|
||||
alloc,
|
||||
md,
|
||||
field.name,
|
||||
@field(v, field.name),
|
||||
);
|
||||
.Struct => |info| {
|
||||
if (@hasDecl(T, "encodeForInspector"))
|
||||
try v.encodeForInspector(alloc, md)
|
||||
else inline for (info.fields) |field| {
|
||||
try encodeMetadataSingle(
|
||||
alloc,
|
||||
md,
|
||||
field.name,
|
||||
@field(v, field.name),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
.Optional => {
|
||||
if (v) |v1| {
|
||||
try encodeMetadata(alloc, md, v1);
|
||||
} else {
|
||||
try md.put("data", try alloc.dupeZ(u8, "(unset)"));
|
||||
}
|
||||
},
|
||||
|
||||
.Opaque => {
|
||||
try md.put("data", try alloc.dupeZ(u8, "(opaque)"));
|
||||
},
|
||||
|
||||
.Pointer => {
|
||||
try encodeMetadata(alloc, md, v.*);
|
||||
},
|
||||
|
||||
else => {
|
||||
@compileLog(T);
|
||||
@compileError("unsupported type, see log");
|
||||
try md.put("data", try alloc.dupeZ(u8, "(unknown)"));
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -231,6 +250,11 @@ pub const VTEvent = struct {
|
||||
try md.put(key, try alloc.dupeZ(u8, "(unset)"));
|
||||
},
|
||||
|
||||
.Int => try md.put(
|
||||
key,
|
||||
try std.fmt.allocPrintZ(alloc, "{d}", .{value}),
|
||||
),
|
||||
|
||||
.Bool => try md.put(
|
||||
key,
|
||||
try alloc.dupeZ(u8, if (value) "true" else "false"),
|
||||
@ -246,23 +270,19 @@ pub const VTEvent = struct {
|
||||
const tag_name = @tagName(@as(Tag, value));
|
||||
inline for (u.fields) |field| {
|
||||
if (std.mem.eql(u8, field.name, tag_name)) {
|
||||
const s = if (field.type == void)
|
||||
try alloc.dupeZ(u8, tag_name)
|
||||
else
|
||||
try std.fmt.allocPrintZ(alloc, "{s}={}", .{
|
||||
tag_name,
|
||||
@field(value, field.name),
|
||||
});
|
||||
|
||||
try md.put(key, s);
|
||||
try encodeMetadataSingle(alloc, md, tag_name, @field(value, field.name));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.Struct => try md.put(
|
||||
key,
|
||||
try alloc.dupeZ(u8, @typeName(Value)),
|
||||
),
|
||||
.Struct => {
|
||||
try md.put(
|
||||
key,
|
||||
try alloc.dupeZ(u8, @typeName(Value)),
|
||||
);
|
||||
},
|
||||
|
||||
.Void => try md.put(key, try alloc.dupeZ(u8, "(void)")),
|
||||
|
||||
else => switch (Value) {
|
||||
u8 => try md.put(
|
||||
@ -272,9 +292,11 @@ pub const VTEvent = struct {
|
||||
|
||||
[]const u8 => try md.put(key, try alloc.dupeZ(u8, value)),
|
||||
|
||||
else => |T| {
|
||||
@compileLog(T);
|
||||
@compileError("unsupported type, see log");
|
||||
else => {
|
||||
var l = std.ArrayList(u8).init(alloc);
|
||||
errdefer l.deinit();
|
||||
try std.json.stringify(value, .{}, l.writer());
|
||||
try md.put(key, try l.toOwnedSliceSentinel(0));
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const key = @import("kitty/key.zig");
|
||||
pub const color = @import("kitty/color.zig");
|
||||
pub const desktop = @import("kitty/desktop.zig");
|
||||
pub const graphics = @import("kitty/graphics.zig");
|
||||
|
||||
pub const KeyFlags = key.Flags;
|
||||
|
1046
src/terminal/kitty/desktop.zig
Normal file
1046
src/terminal/kitty/desktop.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -149,6 +149,10 @@ pub const Command = union(enum) {
|
||||
body: []const u8,
|
||||
},
|
||||
|
||||
/// Kitty desktop notifications (OSC 99)
|
||||
/// https://sw.kovidgoyal.net/kitty/desktop-notifications/
|
||||
kitty_desktop_notification: ?*kitty.desktop.KittyDesktopNotification,
|
||||
|
||||
/// Start a hyperlink (OSC 8)
|
||||
hyperlink_start: struct {
|
||||
id: ?[]const u8 = null,
|
||||
@ -267,6 +271,7 @@ pub const Parser = struct {
|
||||
@"777",
|
||||
@"8",
|
||||
@"9",
|
||||
@"99",
|
||||
|
||||
// OSC 10 is used to query or set the current foreground color.
|
||||
query_fg_color,
|
||||
@ -322,6 +327,11 @@ pub const Parser = struct {
|
||||
// https://sw.kovidgoyal.net/kitty/color-stack/#id1
|
||||
kitty_color_protocol_key,
|
||||
kitty_color_protocol_value,
|
||||
|
||||
// Kitty desktop notifications
|
||||
// https://sw.kovidgoyal.net/kitty/desktop-notifications/
|
||||
kitty_desktop_notification_metadata,
|
||||
kitty_desktop_notification_payload,
|
||||
};
|
||||
|
||||
/// This must be called to clean up any allocated memory.
|
||||
@ -361,6 +371,14 @@ pub const Parser = struct {
|
||||
v.list.deinit();
|
||||
self.command = default;
|
||||
},
|
||||
.kitty_desktop_notification => |v| {
|
||||
if (v) |k| {
|
||||
k.deinit();
|
||||
self.alloc.?.destroy(k);
|
||||
}
|
||||
self.command.kitty_desktop_notification = null;
|
||||
self.command = default;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@ -734,6 +752,7 @@ pub const Parser = struct {
|
||||
},
|
||||
|
||||
.@"9" => switch (c) {
|
||||
'9' => self.state = .@"99",
|
||||
';' => {
|
||||
self.command = .{ .show_desktop_notification = .{
|
||||
.title = "",
|
||||
@ -747,6 +766,30 @@ pub const Parser = struct {
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"99" => switch (c) {
|
||||
';' => kitty: {
|
||||
if (self.alloc == null) {
|
||||
log.warn("OSC 99 (Kitty desktop notifications) requires an allocator, but none was provided", .{});
|
||||
self.state = .invalid;
|
||||
break :kitty;
|
||||
}
|
||||
self.state = .kitty_desktop_notification_metadata;
|
||||
self.buf_start = self.buf_idx;
|
||||
},
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.kitty_desktop_notification_metadata => switch (c) {
|
||||
';' => {
|
||||
self.temp_state = .{ .key = self.buf[self.buf_start .. self.buf_idx - 1] };
|
||||
self.state = .kitty_desktop_notification_payload;
|
||||
self.buf_start = self.buf_idx;
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
|
||||
.kitty_desktop_notification_payload => {},
|
||||
|
||||
.query_fg_color => switch (c) {
|
||||
'?' => {
|
||||
self.command = .{ .report_color = .{ .kind = .foreground } };
|
||||
@ -1084,6 +1127,40 @@ pub const Parser = struct {
|
||||
/// is the final character in the OSC sequence. This is used to determine
|
||||
/// the response terminator.
|
||||
pub fn end(self: *Parser, terminator_ch: ?u8) ?Command {
|
||||
switch (self.state) {
|
||||
.kitty_desktop_notification_metadata => {
|
||||
self.state = .invalid;
|
||||
self.complete = false;
|
||||
},
|
||||
.kitty_desktop_notification_payload => {
|
||||
self.command = .{
|
||||
.kitty_desktop_notification = k: {
|
||||
const alloc = self.alloc orelse {
|
||||
log.warn("kitty desktop notification requires an allocator", .{});
|
||||
self.state = .invalid;
|
||||
self.complete = false;
|
||||
break :k null;
|
||||
};
|
||||
const k = alloc.create(kitty.desktop.KittyDesktopNotification) catch {
|
||||
self.state = .invalid;
|
||||
self.complete = false;
|
||||
break :k null;
|
||||
};
|
||||
k.init(alloc, self) catch {
|
||||
k.deinit();
|
||||
alloc.destroy(k);
|
||||
self.state = .invalid;
|
||||
self.complete = false;
|
||||
break :k null;
|
||||
};
|
||||
self.complete = true;
|
||||
break :k k;
|
||||
},
|
||||
};
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (!self.complete) {
|
||||
log.warn("invalid OSC command: {s}", .{self.buf[0..self.buf_idx]});
|
||||
return null;
|
||||
@ -1104,6 +1181,11 @@ pub const Parser = struct {
|
||||
switch (self.command) {
|
||||
.report_color => |*c| c.terminator = Terminator.init(terminator_ch),
|
||||
.kitty_color_protocol => |*c| c.terminator = Terminator.init(terminator_ch),
|
||||
.kitty_desktop_notification => |v| {
|
||||
if (v) |d| {
|
||||
d.terminator = Terminator.init(terminator_ch);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
@ -1434,6 +1434,11 @@ pub fn Stream(comptime Handler: type) type {
|
||||
} else log.warn("unimplemented OSC callback: {}", .{cmd});
|
||||
},
|
||||
|
||||
.kitty_desktop_notification => |v| {
|
||||
_ = v;
|
||||
log.warn("ignoring kitty desktop notification", .{});
|
||||
},
|
||||
|
||||
.hyperlink_start => |v| {
|
||||
if (@hasDecl(T, "startHyperlink")) {
|
||||
try self.handler.startHyperlink(v.uri, v.id);
|
||||
|
Reference in New Issue
Block a user