sgr parsing can parse multiple

This commit is contained in:
Mitchell Hashimoto
2022-05-12 16:20:30 -07:00
parent 5743d2a232
commit 8400b683c4

View File

@ -24,21 +24,39 @@ pub const Attribute = union(enum) {
}; };
}; };
/// Parse a set of parameters to a SGR command into an attribute. /// Parser parses the attributes from a list of SGR parameters.
pub fn parse(params: []const u16) Attribute { pub const Parser = struct {
// No parameters means unset params: []const u16,
if (params.len == 0) return .{ .unset = {} }; idx: usize = 0,
switch (params[0]) { /// Next returns the next attribute or null if there are no more attributes.
0 => if (params.len == 1) return .{ .unset = {} }, pub fn next(self: *Parser) ?Attribute {
if (self.idx > self.params.len) return null;
// Implicitly means unset
if (self.params.len == 0) {
self.idx += 1;
return Attribute{ .unset = {} };
}
const slice = self.params[self.idx..self.params.len];
self.idx += 1;
// Our last one will have an idx be the last value.
if (slice.len == 0) return null;
switch (slice[0]) {
0 => return Attribute{ .unset = {} },
38 => if (slice.len >= 5 and slice[1] == 2) {
self.idx += 4;
38 => if ((params.len == 5 or params.len == 6) and params[1] == 2) {
// In the 6-len form, ignore the 3rd param. // In the 6-len form, ignore the 3rd param.
const rgb = params[params.len - 3 .. params.len]; const rgb = slice[2..5];
// We use @truncate because the value should be 0 to 255. If // We use @truncate because the value should be 0 to 255. If
// it isn't, the behavior is undefined so we just... truncate it. // it isn't, the behavior is undefined so we just... truncate it.
return .{ return Attribute{
.direct_color_fg = .{ .direct_color_fg = .{
.r = @truncate(u8, rgb[0]), .r = @truncate(u8, rgb[0]),
.g = @truncate(u8, rgb[1]), .g = @truncate(u8, rgb[1]),
@ -47,13 +65,15 @@ pub fn parse(params: []const u16) Attribute {
}; };
}, },
48 => if ((params.len == 5 or params.len == 6) and params[1] == 2) { 48 => if (slice.len >= 5 and slice[1] == 2) {
self.idx += 4;
// In the 6-len form, ignore the 3rd param. // In the 6-len form, ignore the 3rd param.
const rgb = params[params.len - 3 .. params.len]; const rgb = slice[2..5];
// We use @truncate because the value should be 0 to 255. If // We use @truncate because the value should be 0 to 255. If
// it isn't, the behavior is undefined so we just... truncate it. // it isn't, the behavior is undefined so we just... truncate it.
return .{ return Attribute{
.direct_color_bg = .{ .direct_color_bg = .{
.r = @truncate(u8, rgb[0]), .r = @truncate(u8, rgb[0]),
.g = @truncate(u8, rgb[1]), .g = @truncate(u8, rgb[1]),
@ -65,49 +85,44 @@ pub fn parse(params: []const u16) Attribute {
else => {}, else => {},
} }
return .{ .unknown = params }; return Attribute{ .unknown = slice };
}
};
fn testParse(params: []const u16) Attribute {
var p: Parser = .{ .params = params };
return p.next().?;
} }
test "sgr: parse" { test "sgr: Parser" {
try testing.expect(parse(&[_]u16{}) == .unset); try testing.expect(testParse(&[_]u16{}) == .unset);
try testing.expect(parse(&[_]u16{0}) == .unset); try testing.expect(testParse(&[_]u16{0}) == .unset);
try testing.expect(parse(&[_]u16{ 0, 1 }) == .unknown);
{ {
const v = parse(&[_]u16{ 38, 2, 40, 44, 52 }); const v = testParse(&[_]u16{ 38, 2, 40, 44, 52 });
try testing.expect(v == .direct_color_fg); try testing.expect(v == .direct_color_fg);
try testing.expectEqual(@as(u8, 40), v.direct_color_fg.r); 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, 44), v.direct_color_fg.g);
try testing.expectEqual(@as(u8, 52), v.direct_color_fg.b); try testing.expectEqual(@as(u8, 52), v.direct_color_fg.b);
} }
{ try testing.expect(testParse(&[_]u16{ 38, 2, 44, 52 }) == .unknown);
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 }); const v = testParse(&[_]u16{ 48, 2, 40, 44, 52 });
try testing.expect(v == .direct_color_bg); try testing.expect(v == .direct_color_bg);
try testing.expectEqual(@as(u8, 40), v.direct_color_bg.r); 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, 44), v.direct_color_bg.g);
try testing.expectEqual(@as(u8, 52), v.direct_color_bg.b); try testing.expectEqual(@as(u8, 52), v.direct_color_bg.b);
} }
{ try testing.expect(testParse(&[_]u16{ 48, 2, 44, 52 }) == .unknown);
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); test "sgr: Parser multiple" {
try testing.expect(parse(&[_]u16{ 48, 2, 22, 22, 40, 44, 52 }) == .unknown); var p: Parser = .{ .params = &[_]u16{ 0, 38, 2, 40, 44, 52 } };
try testing.expect(p.next().? == .unset);
try testing.expect(p.next().? == .direct_color_fg);
try testing.expect(p.next() == null);
try testing.expect(p.next() == null);
} }