mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
terminal: move kitty color structs out to kitty package
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
//! Types and functions related to Kitty protocols.
|
//! Types and functions related to Kitty protocols.
|
||||||
|
|
||||||
const key = @import("kitty/key.zig");
|
const key = @import("kitty/key.zig");
|
||||||
|
pub const color = @import("kitty/color.zig");
|
||||||
pub const graphics = @import("kitty/graphics.zig");
|
pub const graphics = @import("kitty/graphics.zig");
|
||||||
|
|
||||||
pub const KeyFlags = key.Flags;
|
pub const KeyFlags = key.Flags;
|
||||||
|
92
src/terminal/kitty/color.zig
Normal file
92
src/terminal/kitty/color.zig
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const terminal = @import("../main.zig");
|
||||||
|
const RGB = terminal.color.RGB;
|
||||||
|
const Terminator = terminal.osc.Terminator;
|
||||||
|
|
||||||
|
pub const OSC = struct {
|
||||||
|
pub const Request = union(enum) {
|
||||||
|
query: Kind,
|
||||||
|
set: struct { key: Kind, color: RGB },
|
||||||
|
reset: Kind,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// list of requests
|
||||||
|
list: std.ArrayList(Request),
|
||||||
|
|
||||||
|
/// We must reply with the same string terminator (ST) as used in the
|
||||||
|
/// request.
|
||||||
|
terminator: Terminator = .st,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Kind = enum(u9) {
|
||||||
|
// Make sure that this stays in sync with the higest numbered enum
|
||||||
|
// value.
|
||||||
|
pub const max: u9 = 263;
|
||||||
|
|
||||||
|
// These _must_ start at 256 since enum values 0-255 are reserved
|
||||||
|
// for the palette.
|
||||||
|
foreground = 256,
|
||||||
|
background = 257,
|
||||||
|
selection_foreground = 258,
|
||||||
|
selection_background = 259,
|
||||||
|
cursor = 260,
|
||||||
|
cursor_text = 261,
|
||||||
|
visual_bell = 262,
|
||||||
|
second_transparent_background = 263,
|
||||||
|
_,
|
||||||
|
|
||||||
|
/// Return the palette index that this kind is representing
|
||||||
|
/// or null if its a special color.
|
||||||
|
pub fn palette(self: Kind) ?u8 {
|
||||||
|
return std.math.cast(u8, @intFromEnum(self)) orelse null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(
|
||||||
|
self: Kind,
|
||||||
|
comptime layout: []const u8,
|
||||||
|
opts: std.fmt.FormatOptions,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
_ = layout;
|
||||||
|
_ = opts;
|
||||||
|
|
||||||
|
// Format as a number if its a palette color otherwise
|
||||||
|
// format as a string.
|
||||||
|
if (self.palette()) |idx| {
|
||||||
|
try writer.print("{}", .{idx});
|
||||||
|
} else {
|
||||||
|
try writer.print("{s}", .{@tagName(self)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "OSC: kitty color protocol kind" {
|
||||||
|
const info = @typeInfo(Kind);
|
||||||
|
|
||||||
|
try std.testing.expectEqual(false, info.Enum.is_exhaustive);
|
||||||
|
|
||||||
|
var min: usize = std.math.maxInt(info.Enum.tag_type);
|
||||||
|
var max: usize = 0;
|
||||||
|
|
||||||
|
inline for (info.Enum.fields) |field| {
|
||||||
|
if (field.value > max) max = field.value;
|
||||||
|
if (field.value < min) min = field.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
try std.testing.expect(min >= 256);
|
||||||
|
try std.testing.expect(max == Kind.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "OSC: kitty color protocol kind string" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
{
|
||||||
|
const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind.foreground});
|
||||||
|
try testing.expectEqualStrings("foreground", actual);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const actual = try std.fmt.bufPrint(&buf, "{}", .{@as(Kind, @enumFromInt(42))});
|
||||||
|
try testing.expectEqualStrings("42", actual);
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ const mem = std.mem;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const RGB = @import("color.zig").RGB;
|
const RGB = @import("color.zig").RGB;
|
||||||
|
const kitty = @import("kitty.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.osc);
|
const log = std.log.scoped(.osc);
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ pub const Command = union(enum) {
|
|||||||
|
|
||||||
/// Kitty color protocl, OSC 21
|
/// Kitty color protocl, OSC 21
|
||||||
/// https://sw.kovidgoyal.net/kitty/color-stack/#id1
|
/// https://sw.kovidgoyal.net/kitty/color-stack/#id1
|
||||||
kitty_color_protocol: KittyColorProtocol,
|
kitty_color_protocol: kitty.color.OSC,
|
||||||
|
|
||||||
/// Show a desktop notification (OSC 9 or OSC 777)
|
/// Show a desktop notification (OSC 9 or OSC 777)
|
||||||
show_desktop_notification: struct {
|
show_desktop_notification: struct {
|
||||||
@ -172,66 +173,6 @@ pub const Command = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const KittyColorProtocol = struct {
|
|
||||||
const Kind = enum(u9) {
|
|
||||||
// Make sure that this stays in sync with the higest numbered enum
|
|
||||||
// value.
|
|
||||||
const max: u9 = 263;
|
|
||||||
|
|
||||||
// These _must_ start at 256 since enum values 0-255 are reserved
|
|
||||||
// for the palette.
|
|
||||||
foreground = 256,
|
|
||||||
background = 257,
|
|
||||||
selection_foreground = 258,
|
|
||||||
selection_background = 259,
|
|
||||||
cursor = 260,
|
|
||||||
cursor_text = 261,
|
|
||||||
visual_bell = 262,
|
|
||||||
second_transparent_background = 263,
|
|
||||||
_,
|
|
||||||
|
|
||||||
/// Return the palette index that this kind is representing
|
|
||||||
/// or null if its a special color.
|
|
||||||
pub fn palette(self: Kind) ?u8 {
|
|
||||||
return std.math.cast(u8, @intFromEnum(self)) orelse null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format(
|
|
||||||
self: Kind,
|
|
||||||
comptime layout: []const u8,
|
|
||||||
opts: std.fmt.FormatOptions,
|
|
||||||
writer: anytype,
|
|
||||||
) !void {
|
|
||||||
_ = layout;
|
|
||||||
_ = opts;
|
|
||||||
|
|
||||||
// Format as a number if its a palette color otherwise
|
|
||||||
// format as a string.
|
|
||||||
if (self.palette()) |idx| {
|
|
||||||
try writer.print("{}", .{idx});
|
|
||||||
} else {
|
|
||||||
try writer.print("{s}", .{@tagName(self)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Request = union(enum) {
|
|
||||||
query: Kind,
|
|
||||||
set: struct {
|
|
||||||
key: Kind,
|
|
||||||
color: RGB,
|
|
||||||
},
|
|
||||||
reset: Kind,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// list of requests
|
|
||||||
list: std.ArrayList(Request),
|
|
||||||
|
|
||||||
/// We must reply with the same string terminator (ST) as used in the
|
|
||||||
/// request.
|
|
||||||
terminator: Terminator = .st,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The terminator used to end an OSC command. For OSC commands that demand
|
/// The terminator used to end an OSC command. For OSC commands that demand
|
||||||
@ -538,7 +479,7 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
self.command = .{
|
self.command = .{
|
||||||
.kitty_color_protocol = .{
|
.kitty_color_protocol = .{
|
||||||
.list = std.ArrayList(Command.KittyColorProtocol.Request).init(alloc),
|
.list = std.ArrayList(kitty.color.OSC.Request).init(alloc),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1067,8 +1008,8 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
// For our key, we first try to parse it as a special key. If that
|
// For our key, we first try to parse it as a special key. If that
|
||||||
// doesn't work then we try to parse it as a number for a palette.
|
// doesn't work then we try to parse it as a number for a palette.
|
||||||
const key: Command.KittyColorProtocol.Kind = std.meta.stringToEnum(
|
const key: kitty.color.Kind = std.meta.stringToEnum(
|
||||||
Command.KittyColorProtocol.Kind,
|
kitty.color.Kind,
|
||||||
self.temp_state.key,
|
self.temp_state.key,
|
||||||
) orelse @enumFromInt(std.fmt.parseUnsigned(
|
) orelse @enumFromInt(std.fmt.parseUnsigned(
|
||||||
u8,
|
u8,
|
||||||
@ -1088,7 +1029,7 @@ pub const Parser = struct {
|
|||||||
switch (self.command) {
|
switch (self.command) {
|
||||||
.kitty_color_protocol => |*v| {
|
.kitty_color_protocol => |*v| {
|
||||||
// Cap our allocation amount for our list.
|
// Cap our allocation amount for our list.
|
||||||
if (v.list.items.len >= @as(usize, Command.KittyColorProtocol.Kind.max) * 2) {
|
if (v.list.items.len >= @as(usize, kitty.color.Kind.max) * 2) {
|
||||||
self.state = .invalid;
|
self.state = .invalid;
|
||||||
log.warn("exceeded limit for number of keys in kitty color protocol, ignoring", .{});
|
log.warn("exceeded limit for number of keys in kitty color protocol, ignoring", .{});
|
||||||
return;
|
return;
|
||||||
@ -1705,12 +1646,12 @@ test "OSC: kitty color protocol" {
|
|||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[0];
|
const item = cmd.kitty_color_protocol.list.items[0];
|
||||||
try testing.expect(item == .query);
|
try testing.expect(item == .query);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.foreground, item.query);
|
try testing.expectEqual(kitty.color.Kind.foreground, item.query);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[1];
|
const item = cmd.kitty_color_protocol.list.items[1];
|
||||||
try testing.expect(item == .set);
|
try testing.expect(item == .set);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.background, item.set.key);
|
try testing.expectEqual(kitty.color.Kind.background, item.set.key);
|
||||||
try testing.expectEqual(@as(u8, 0xf0), item.set.color.r);
|
try testing.expectEqual(@as(u8, 0xf0), item.set.color.r);
|
||||||
try testing.expectEqual(@as(u8, 0xf8), item.set.color.g);
|
try testing.expectEqual(@as(u8, 0xf8), item.set.color.g);
|
||||||
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
||||||
@ -1718,7 +1659,7 @@ test "OSC: kitty color protocol" {
|
|||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[2];
|
const item = cmd.kitty_color_protocol.list.items[2];
|
||||||
try testing.expect(item == .set);
|
try testing.expect(item == .set);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.cursor, item.set.key);
|
try testing.expectEqual(kitty.color.Kind.cursor, item.set.key);
|
||||||
try testing.expectEqual(@as(u8, 0xf0), item.set.color.r);
|
try testing.expectEqual(@as(u8, 0xf0), item.set.color.r);
|
||||||
try testing.expectEqual(@as(u8, 0xf8), item.set.color.g);
|
try testing.expectEqual(@as(u8, 0xf8), item.set.color.g);
|
||||||
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
||||||
@ -1726,22 +1667,22 @@ test "OSC: kitty color protocol" {
|
|||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[3];
|
const item = cmd.kitty_color_protocol.list.items[3];
|
||||||
try testing.expect(item == .reset);
|
try testing.expect(item == .reset);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.cursor_text, item.reset);
|
try testing.expectEqual(kitty.color.Kind.cursor_text, item.reset);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[4];
|
const item = cmd.kitty_color_protocol.list.items[4];
|
||||||
try testing.expect(item == .reset);
|
try testing.expect(item == .reset);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.visual_bell, item.reset);
|
try testing.expectEqual(kitty.color.Kind.visual_bell, item.reset);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[5];
|
const item = cmd.kitty_color_protocol.list.items[5];
|
||||||
try testing.expect(item == .query);
|
try testing.expect(item == .query);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.selection_background, item.query);
|
try testing.expectEqual(kitty.color.Kind.selection_background, item.query);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[6];
|
const item = cmd.kitty_color_protocol.list.items[6];
|
||||||
try testing.expect(item == .set);
|
try testing.expect(item == .set);
|
||||||
try testing.expectEqual(Command.KittyColorProtocol.Kind.selection_background, item.set.key);
|
try testing.expectEqual(kitty.color.Kind.selection_background, item.set.key);
|
||||||
try testing.expectEqual(@as(u8, 0xaa), item.set.color.r);
|
try testing.expectEqual(@as(u8, 0xaa), item.set.color.r);
|
||||||
try testing.expectEqual(@as(u8, 0xbb), item.set.color.g);
|
try testing.expectEqual(@as(u8, 0xbb), item.set.color.g);
|
||||||
try testing.expectEqual(@as(u8, 0xcc), item.set.color.b);
|
try testing.expectEqual(@as(u8, 0xcc), item.set.color.b);
|
||||||
@ -1749,12 +1690,12 @@ test "OSC: kitty color protocol" {
|
|||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[7];
|
const item = cmd.kitty_color_protocol.list.items[7];
|
||||||
try testing.expect(item == .query);
|
try testing.expect(item == .query);
|
||||||
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, @enumFromInt(2)), item.query);
|
try testing.expectEqual(@as(kitty.color.Kind, @enumFromInt(2)), item.query);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const item = cmd.kitty_color_protocol.list.items[8];
|
const item = cmd.kitty_color_protocol.list.items[8];
|
||||||
try testing.expect(item == .set);
|
try testing.expect(item == .set);
|
||||||
try testing.expectEqual(@as(Command.KittyColorProtocol.Kind, @enumFromInt(3)), item.set.key);
|
try testing.expectEqual(@as(kitty.color.Kind, @enumFromInt(3)), item.set.key);
|
||||||
try testing.expectEqual(@as(u8, 0xff), item.set.color.r);
|
try testing.expectEqual(@as(u8, 0xff), item.set.color.r);
|
||||||
try testing.expectEqual(@as(u8, 0xff), item.set.color.g);
|
try testing.expectEqual(@as(u8, 0xff), item.set.color.g);
|
||||||
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
try testing.expectEqual(@as(u8, 0xff), item.set.color.b);
|
||||||
@ -1771,35 +1712,3 @@ test "OSC: kitty color protocol without allocator" {
|
|||||||
for (input) |ch| p.next(ch);
|
for (input) |ch| p.next(ch);
|
||||||
try testing.expect(p.end('\x1b') == null);
|
try testing.expect(p.end('\x1b') == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "OSC: kitty color protocol kind" {
|
|
||||||
const info = @typeInfo(Command.KittyColorProtocol.Kind);
|
|
||||||
|
|
||||||
try std.testing.expectEqual(false, info.Enum.is_exhaustive);
|
|
||||||
|
|
||||||
var min: usize = std.math.maxInt(info.Enum.tag_type);
|
|
||||||
var max: usize = 0;
|
|
||||||
|
|
||||||
inline for (info.Enum.fields) |field| {
|
|
||||||
if (field.value > max) max = field.value;
|
|
||||||
if (field.value < min) min = field.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
try std.testing.expect(min >= 256);
|
|
||||||
try std.testing.expect(max == Command.KittyColorProtocol.Kind.max);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "OSC: kitty color protocol kind string" {
|
|
||||||
const testing = std.testing;
|
|
||||||
const Kind = Command.KittyColorProtocol.Kind;
|
|
||||||
|
|
||||||
var buf: [256]u8 = undefined;
|
|
||||||
{
|
|
||||||
const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind.foreground});
|
|
||||||
try testing.expectEqualStrings("foreground", actual);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const actual = try std.fmt.bufPrint(&buf, "{}", .{@as(Kind, @enumFromInt(42))});
|
|
||||||
try testing.expectEqualStrings("42", actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1302,7 +1302,10 @@ pub const StreamHandler = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendKittyColorReport(self: *StreamHandler, request: terminal.osc.Command.KittyColorProtocol) !void {
|
pub fn sendKittyColorReport(
|
||||||
|
self: *StreamHandler,
|
||||||
|
request: terminal.kitty.color.OSC,
|
||||||
|
) !void {
|
||||||
var buf = std.ArrayList(u8).init(self.alloc);
|
var buf = std.ArrayList(u8).init(self.alloc);
|
||||||
defer buf.deinit();
|
defer buf.deinit();
|
||||||
const writer = buf.writer();
|
const writer = buf.writer();
|
||||||
|
Reference in New Issue
Block a user