mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
terminal sgr attribute parsing
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
const stream = @import("stream.zig");
|
||||
const ansi = @import("ansi.zig");
|
||||
const csi = @import("csi.zig");
|
||||
const sgr = @import("sgr.zig");
|
||||
|
||||
pub const Terminal = @import("Terminal.zig");
|
||||
pub const Parser = @import("Parser.zig");
|
||||
@ -8,12 +9,14 @@ pub const Stream = stream.Stream;
|
||||
pub const Mode = ansi.Mode;
|
||||
pub const EraseDisplay = csi.EraseDisplay;
|
||||
pub const EraseLine = csi.EraseLine;
|
||||
pub const Attribute = sgr.Attribute;
|
||||
|
||||
// Not exported because they're just used for tests.
|
||||
|
||||
test {
|
||||
_ = ansi;
|
||||
_ = csi;
|
||||
_ = sgr;
|
||||
_ = stream;
|
||||
_ = Parser;
|
||||
_ = Terminal;
|
||||
|
113
src/terminal/sgr.zig
Normal file
113
src/terminal/sgr.zig
Normal file
@ -0,0 +1,113 @@
|
||||
//! SGR (Select Graphic Rendition) attribute parsing and types.
|
||||
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
|
||||
/// Attribute type for SGR
|
||||
pub const Attribute = union(enum) {
|
||||
/// Unset all attributes
|
||||
unset: void,
|
||||
|
||||
/// Unknown attribute, the raw CSI command parameters are here.
|
||||
unknown: []const u16,
|
||||
|
||||
/// Set foreground color as RGB values.
|
||||
direct_color_fg: RGB,
|
||||
|
||||
/// Set background color as RGB values.
|
||||
direct_color_bg: RGB,
|
||||
|
||||
pub const RGB = struct {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
};
|
||||
};
|
||||
|
||||
/// Parse a set of parameters to a SGR command into an attribute.
|
||||
pub fn parse(params: []const u16) Attribute {
|
||||
// No parameters means unset
|
||||
if (params.len == 0) return .{ .unset = {} };
|
||||
|
||||
switch (params[0]) {
|
||||
0 => if (params.len == 1) return .{ .unset = {} },
|
||||
|
||||
38 => if ((params.len == 5 or params.len == 6) and params[1] == 2) {
|
||||
// In the 6-len form, ignore the 3rd param.
|
||||
const rgb = params[params.len - 3 .. params.len];
|
||||
|
||||
// We use @truncate because the value should be 0 to 255. If
|
||||
// it isn't, the behavior is undefined so we just... truncate it.
|
||||
return .{
|
||||
.direct_color_fg = .{
|
||||
.r = @truncate(u8, rgb[0]),
|
||||
.g = @truncate(u8, rgb[1]),
|
||||
.b = @truncate(u8, rgb[2]),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
48 => if ((params.len == 5 or params.len == 6) and params[1] == 2) {
|
||||
// In the 6-len form, ignore the 3rd param.
|
||||
const rgb = params[params.len - 3 .. params.len];
|
||||
|
||||
// We use @truncate because the value should be 0 to 255. If
|
||||
// it isn't, the behavior is undefined so we just... truncate it.
|
||||
return .{
|
||||
.direct_color_bg = .{
|
||||
.r = @truncate(u8, rgb[0]),
|
||||
.g = @truncate(u8, rgb[1]),
|
||||
.b = @truncate(u8, rgb[2]),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
else => {},
|
||||
}
|
||||
|
||||
return .{ .unknown = params };
|
||||
}
|
||||
|
||||
test "sgr: parse" {
|
||||
try testing.expect(parse(&[_]u16{}) == .unset);
|
||||
try testing.expect(parse(&[_]u16{0}) == .unset);
|
||||
try testing.expect(parse(&[_]u16{ 0, 1 }) == .unknown);
|
||||
|
||||
{
|
||||
const v = parse(&[_]u16{ 38, 2, 40, 44, 52 });
|
||||
try testing.expect(v == .direct_color_fg);
|
||||
try testing.expectEqual(@as(u8, 40), v.direct_color_fg.r);
|
||||
try testing.expectEqual(@as(u8, 44), v.direct_color_fg.g);
|
||||
try testing.expectEqual(@as(u8, 52), v.direct_color_fg.b);
|
||||
}
|
||||
|
||||
{
|
||||
const v = parse(&[_]u16{ 38, 2, 22, 40, 44, 52 });
|
||||
try testing.expect(v == .direct_color_fg);
|
||||
try testing.expectEqual(@as(u8, 40), v.direct_color_fg.r);
|
||||
try testing.expectEqual(@as(u8, 44), v.direct_color_fg.g);
|
||||
try testing.expectEqual(@as(u8, 52), v.direct_color_fg.b);
|
||||
}
|
||||
|
||||
try testing.expect(parse(&[_]u16{ 38, 2, 44, 52 }) == .unknown);
|
||||
try testing.expect(parse(&[_]u16{ 38, 2, 22, 22, 40, 44, 52 }) == .unknown);
|
||||
|
||||
{
|
||||
const v = parse(&[_]u16{ 48, 2, 40, 44, 52 });
|
||||
try testing.expect(v == .direct_color_bg);
|
||||
try testing.expectEqual(@as(u8, 40), v.direct_color_bg.r);
|
||||
try testing.expectEqual(@as(u8, 44), v.direct_color_bg.g);
|
||||
try testing.expectEqual(@as(u8, 52), v.direct_color_bg.b);
|
||||
}
|
||||
|
||||
{
|
||||
const v = parse(&[_]u16{ 48, 2, 22, 40, 44, 52 });
|
||||
try testing.expect(v == .direct_color_bg);
|
||||
try testing.expectEqual(@as(u8, 40), v.direct_color_bg.r);
|
||||
try testing.expectEqual(@as(u8, 44), v.direct_color_bg.g);
|
||||
try testing.expectEqual(@as(u8, 52), v.direct_color_bg.b);
|
||||
}
|
||||
|
||||
try testing.expect(parse(&[_]u16{ 48, 2, 44, 52 }) == .unknown);
|
||||
try testing.expect(parse(&[_]u16{ 48, 2, 22, 22, 40, 44, 52 }) == .unknown);
|
||||
}
|
Reference in New Issue
Block a user