diff --git a/src/terminal/sgr.zig b/src/terminal/sgr.zig index 7dca98c96..cdf39657b 100644 --- a/src/terminal/sgr.zig +++ b/src/terminal/sgr.zig @@ -189,26 +189,39 @@ pub const Parser = struct { .@"8_fg" = @enumFromInt(slice[0] - 30), }, - 38 => if (slice.len >= 5 and slice[1] == 2) { - self.idx += 4; + 38 => if (slice.len >= 2) switch (slice[1]) { + // `2` indicates direct-color (r, g, b). + // We need at least 3 more params for this to make sense. + 2 => if (slice.len >= 5) { + self.idx += 4; + // When a colon separator is used, there may or may not be + // a color space identifier as the third param, which we + // need to ignore (it has no standardized behavior). + const rgb = if (slice.len == 5 or !self.colon) + slice[2..5] + else rgb: { + self.idx += 1; + break :rgb slice[3..6]; + }; - // In the 6-len form, ignore the 3rd param. - const rgb = slice[2..5]; - - // 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 Attribute{ - .direct_color_fg = .{ - .r = @truncate(rgb[0]), - .g = @truncate(rgb[1]), - .b = @truncate(rgb[2]), - }, - }; - } else if (slice.len >= 3 and slice[1] == 5) { - self.idx += 2; - return Attribute{ - .@"256_fg" = @truncate(slice[2]), - }; + // 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 Attribute{ + .direct_color_fg = .{ + .r = @truncate(rgb[0]), + .g = @truncate(rgb[1]), + .b = @truncate(rgb[2]), + }, + }; + }, + // `5` indicates indexed color. + 5 => if (slice.len >= 3) { + self.idx += 2; + return Attribute{ + .@"256_fg" = @truncate(slice[2]), + }; + }, + else => {}, }, 39 => return Attribute{ .reset_fg = {} }, @@ -217,26 +230,39 @@ pub const Parser = struct { .@"8_bg" = @enumFromInt(slice[0] - 40), }, - 48 => if (slice.len >= 5 and slice[1] == 2) { - self.idx += 4; + 48 => if (slice.len >= 2) switch (slice[1]) { + // `2` indicates direct-color (r, g, b). + // We need at least 3 more params for this to make sense. + 2 => if (slice.len >= 5) { + self.idx += 4; + // When a colon separator is used, there may or may not be + // a color space identifier as the third param, which we + // need to ignore (it has no standardized behavior). + const rgb = if (slice.len == 5 or !self.colon) + slice[2..5] + else rgb: { + self.idx += 1; + break :rgb slice[3..6]; + }; - // We only support the 5-len form. - const rgb = slice[2..5]; - - // 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 Attribute{ - .direct_color_bg = .{ - .r = @truncate(rgb[0]), - .g = @truncate(rgb[1]), - .b = @truncate(rgb[2]), - }, - }; - } else if (slice.len >= 3 and slice[1] == 5) { - self.idx += 2; - return Attribute{ - .@"256_bg" = @truncate(slice[2]), - }; + // 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 Attribute{ + .direct_color_bg = .{ + .r = @truncate(rgb[0]), + .g = @truncate(rgb[1]), + .b = @truncate(rgb[2]), + }, + }; + }, + // `5` indicates indexed color. + 5 => if (slice.len >= 3) { + self.idx += 2; + return Attribute{ + .@"256_bg" = @truncate(slice[2]), + }; + }, + else => {}, }, 49 => return Attribute{ .reset_bg = {} }, @@ -244,30 +270,39 @@ pub const Parser = struct { 53 => return Attribute{ .overline = {} }, 55 => return Attribute{ .reset_overline = {} }, - 58 => if (slice.len >= 5 and slice[1] == 2) { - self.idx += 4; + 58 => if (slice.len >= 2) switch (slice[1]) { + // `2` indicates direct-color (r, g, b). + // We need at least 3 more params for this to make sense. + 2 => if (slice.len >= 5) { + self.idx += 4; + // When a colon separator is used, there may or may not be + // a color space identifier as the third param, which we + // need to ignore (it has no standardized behavior). + const rgb = if (slice.len == 5 or !self.colon) + slice[2..5] + else rgb: { + self.idx += 1; + break :rgb slice[3..6]; + }; - // In the 6-len form, ignore the 3rd param. Otherwise, use it. - const rgb = if (slice.len == 5) slice[2..5] else rgb: { - // Consume one more element - self.idx += 1; - break :rgb slice[3..6]; - }; - - // 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 Attribute{ - .underline_color = .{ - .r = @truncate(rgb[0]), - .g = @truncate(rgb[1]), - .b = @truncate(rgb[2]), - }, - }; - } else if (slice.len >= 3 and slice[1] == 5) { - self.idx += 2; - return Attribute{ - .@"256_underline_color" = @truncate(slice[2]), - }; + // 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 Attribute{ + .underline_color = .{ + .r = @truncate(rgb[0]), + .g = @truncate(rgb[1]), + .b = @truncate(rgb[2]), + }, + }; + }, + // `5` indicates indexed color. + 5 => if (slice.len >= 3) { + self.idx += 2; + return Attribute{ + .@"256_underline_color" = @truncate(slice[2]), + }; + }, + else => {}, }, 59 => return Attribute{ .reset_underline_color = {} },