fix(terminal): truecolor SGR with colour space id #41491

libvterm reads the first three sub-parameters of an SGR 38:2 or 48:2 sequence
as R:G:B, so a colour space id shifts the channels: the empty slot becomes red
via CSI_ARG_MISSING truncating to 255, and green and blue move over one.

Skip the colour space id when the colon-separated group holds more than three
arguments. The group length comes from CSI_ARG_HAS_MORE rather than the raw
argument count, so a following semicolon-separated parameter is not consumed.
This commit is contained in:
KBS
2026-08-26 23:10:57 +09:00
committed by GitHub
parent 8d9a798d6d
commit 0346958153
2 changed files with 29 additions and 5 deletions

View File

@@ -90,15 +90,25 @@ static int lookup_colour(const VTermState *state, int palette, const long args[]
VTermColor *col)
{
switch (palette) {
case 2: // RGB mode - 3 args contain colour values directly
if (argcount < 3) {
case 2: { // RGB mode - 3 args contain colour values directly
// ITU-T T.416 places a colour space id before R:G:B, as in "38:2::R:G:B".
// Skip it when this colon-separated group holds more than three arguments.
int grouplen = 0;
while (grouplen < argcount && CSI_ARG_HAS_MORE(args[grouplen])) {
grouplen++;
}
grouplen = grouplen < argcount ? grouplen + 1 : argcount;
const int skip = grouplen > 3 ? 1 : 0;
if (argcount - skip < 3) {
return argcount;
}
vterm_color_rgb(col, (uint8_t)CSI_ARG(args[0]), (uint8_t)CSI_ARG(args[1]),
(uint8_t)CSI_ARG(args[2]));
vterm_color_rgb(col, (uint8_t)CSI_ARG(args[skip]), (uint8_t)CSI_ARG(args[skip + 1]),
(uint8_t)CSI_ARG(args[skip + 2]));
return 3;
return skip + 3;
}
case 5: // XTerm 256-colour mode
if (!argcount || CSI_ARG_IS_MISSING(args[0])) {

View File

@@ -332,6 +332,20 @@ describe(':terminal highlight forwarding', function()
{1:-- TERMINAL --} |
]])
end)
it('handles truecolor SGR with a colour space id', function()
skip(is_os('win'))
tt.feed_termcode('[38:2::255:128:0m')
tt.feed_data('color')
tt.clear_attrs()
tt.feed_data('text')
screen:expect([[
tty ready |
{3:color}text^ |
|*4
{1:-- TERMINAL --} |
]])
end)
end)
--- @param buflocal boolean