termptyesc: fix truecolors parsing + tests
This commit is contained in:
parent
3cc3f3ee2a
commit
add8b71778
|
@ -100,7 +100,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr)
|
||||||
Eina_Unicode *b = *ptr;
|
Eina_Unicode *b = *ptr;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
if (!b)
|
if ((b == NULL) || (*b == '\0'))
|
||||||
{
|
{
|
||||||
*ptr = NULL;
|
*ptr = NULL;
|
||||||
return -CSI_ARG_NO_VALUE;
|
return -CSI_ARG_NO_VALUE;
|
||||||
|
@ -128,6 +128,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr)
|
||||||
if (sum > INT32_MAX/10 )
|
if (sum > INT32_MAX/10 )
|
||||||
{
|
{
|
||||||
ERR("Invalid sequence: argument is too large");
|
ERR("Invalid sequence: argument is too large");
|
||||||
|
ty->decoding_error = EINA_TRUE;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
sum *= 10;
|
sum *= 10;
|
||||||
|
@ -135,7 +136,7 @@ _csi_arg_get(Termpty *ty, Eina_Unicode **ptr)
|
||||||
b++;
|
b++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*b == ';')
|
if ((*b == ';') || (*b == ':'))
|
||||||
{
|
{
|
||||||
if (b[1])
|
if (b[1])
|
||||||
b++;
|
b++;
|
||||||
|
@ -540,41 +541,66 @@ _handle_esc_csi_reset_mode(Termpty *ty, Eina_Unicode cc, Eina_Unicode *b,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_csi_truecolor_arg_get(Eina_Unicode **ptr)
|
_csi_truecolor_arg_get(Termpty *ty, Eina_Unicode **ptr)
|
||||||
{
|
{
|
||||||
Eina_Unicode *b = *ptr;
|
Eina_Unicode *b = *ptr;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
char separator;
|
||||||
|
|
||||||
if (!b)
|
if ((b == NULL) || (*b == '\0'))
|
||||||
goto error;
|
{
|
||||||
|
*ptr = NULL;
|
||||||
|
return -CSI_ARG_NO_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
if ((*b == ';') || (*b == ':'))
|
/* by construction, shall be the same separator as the following ones */
|
||||||
|
separator = *(b-1);
|
||||||
|
if ((separator != ';') && (separator != ':'))
|
||||||
|
{
|
||||||
|
*ptr = NULL;
|
||||||
|
return -CSI_ARG_NO_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*b == separator)
|
||||||
{
|
{
|
||||||
b++;
|
b++;
|
||||||
*ptr = b;
|
*ptr = b;
|
||||||
return 0;
|
return -CSI_ARG_NO_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*b)
|
if (*b == '\0')
|
||||||
goto error;
|
{
|
||||||
|
*ptr = NULL;
|
||||||
|
return -CSI_ARG_NO_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
while ((*b >= '0') && (*b <= '9'))
|
while ((*b >= '0') && (*b <= '9'))
|
||||||
{
|
{
|
||||||
if (sum > INT32_MAX/10 )
|
if (sum > INT32_MAX/10 )
|
||||||
goto error;
|
{
|
||||||
|
*ptr = NULL;
|
||||||
|
ERR("Invalid sequence: argument is too large");
|
||||||
|
ty->decoding_error = EINA_TRUE;
|
||||||
|
return -CSI_ARG_ERROR;
|
||||||
|
}
|
||||||
sum *= 10;
|
sum *= 10;
|
||||||
sum += *b - '0';
|
sum += *b - '0';
|
||||||
b++;
|
b++;
|
||||||
}
|
}
|
||||||
if ((*b == ';') || (*b == ':'))
|
if (*b == separator)
|
||||||
b++;
|
{
|
||||||
|
b++;
|
||||||
*ptr = b;
|
*ptr = b;
|
||||||
|
}
|
||||||
|
else if (*b == '\0')
|
||||||
|
{
|
||||||
|
*ptr = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ptr = b;
|
||||||
|
}
|
||||||
return sum;
|
return sum;
|
||||||
|
|
||||||
error:
|
|
||||||
*ptr = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -631,68 +657,171 @@ _approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0)
|
||||||
static int
|
static int
|
||||||
_handle_esc_csi_truecolor_rgb(Termpty *ty, Eina_Unicode **ptr)
|
_handle_esc_csi_truecolor_rgb(Termpty *ty, Eina_Unicode **ptr)
|
||||||
{
|
{
|
||||||
int r0, g0, b0, other;
|
int r, g, b;
|
||||||
|
Eina_Unicode *u = *ptr;
|
||||||
|
char separator;
|
||||||
|
|
||||||
r0 = _csi_truecolor_arg_get(ptr);
|
if ((u == NULL) || (*u == '\0'))
|
||||||
g0 = _csi_truecolor_arg_get(ptr);
|
|
||||||
b0 = _csi_truecolor_arg_get(ptr);
|
|
||||||
other = _csi_truecolor_arg_get(ptr);
|
|
||||||
if (other >= 0)
|
|
||||||
{
|
{
|
||||||
r0 = g0;
|
return COL_DEF;
|
||||||
g0 = b0;
|
|
||||||
b0 = other;
|
|
||||||
}
|
}
|
||||||
|
separator = *(u-1);
|
||||||
|
|
||||||
if ((r0 < 0) || (g0 < 0) || (b0 < 0))
|
r = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
g = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
b = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
if ((r == -CSI_ARG_ERROR) ||
|
||||||
|
(g == -CSI_ARG_ERROR) ||
|
||||||
|
(b == -CSI_ARG_ERROR))
|
||||||
return COL_DEF;
|
return COL_DEF;
|
||||||
|
|
||||||
return _approximate_truecolor_rgb(ty, r0, g0, b0);
|
if (separator == ':' && *ptr)
|
||||||
|
{
|
||||||
|
if (**ptr != ';')
|
||||||
|
{
|
||||||
|
/* then the first parameter was a color-space-id (ignored) */
|
||||||
|
r = g;
|
||||||
|
g = b;
|
||||||
|
b = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
/* Skip other parameters */
|
||||||
|
while ((*ptr) && (**ptr != ';'))
|
||||||
|
{
|
||||||
|
_csi_truecolor_arg_get(ty, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*ptr) && (**ptr == ';'))
|
||||||
|
{
|
||||||
|
*ptr = (*ptr) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == -CSI_ARG_NO_VALUE)
|
||||||
|
r = 0;
|
||||||
|
if (g == -CSI_ARG_NO_VALUE)
|
||||||
|
g = 0;
|
||||||
|
if (b == -CSI_ARG_NO_VALUE)
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
return _approximate_truecolor_rgb(ty, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_handle_esc_csi_truecolor_cmy(Termpty *ty, Eina_Unicode **ptr)
|
_handle_esc_csi_truecolor_cmy(Termpty *ty, Eina_Unicode **ptr)
|
||||||
{
|
{
|
||||||
int r0, g0, b0, c0, m0, y0;
|
int r, g, b, c, m, y;
|
||||||
|
Eina_Unicode *u = *ptr;
|
||||||
|
char separator;
|
||||||
|
|
||||||
|
if ((u == NULL) || (*u == '\0'))
|
||||||
|
{
|
||||||
|
return COL_DEF;
|
||||||
|
}
|
||||||
|
separator = *(u-1);
|
||||||
|
|
||||||
/* Considering CMY stored as percents */
|
/* Considering CMY stored as percents */
|
||||||
c0 = _csi_truecolor_arg_get(ptr);
|
c = _csi_truecolor_arg_get(ty, ptr);
|
||||||
m0 = _csi_truecolor_arg_get(ptr);
|
m = _csi_truecolor_arg_get(ty, ptr);
|
||||||
y0 = _csi_truecolor_arg_get(ptr);
|
y = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
|
||||||
if ((c0 < 0) || (m0 < 0) || (y0 < 0))
|
if ((c == -CSI_ARG_ERROR) ||
|
||||||
|
(m == -CSI_ARG_ERROR) ||
|
||||||
|
(y == -CSI_ARG_ERROR))
|
||||||
return COL_DEF;
|
return COL_DEF;
|
||||||
|
|
||||||
r0 = 255 - ((c0 * 255) / 100);
|
if (separator == ':' && *ptr)
|
||||||
g0 = 255 - ((m0 * 255) / 100);
|
{
|
||||||
b0 = 255 - ((y0 * 255) / 100);
|
if (**ptr != ';')
|
||||||
|
{
|
||||||
|
/* then the first parameter was a color-space-id (ignored) */
|
||||||
|
c = m;
|
||||||
|
m = y;
|
||||||
|
y = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
/* Skip other parameters */
|
||||||
|
while ((*ptr) && (**ptr != ';'))
|
||||||
|
{
|
||||||
|
_csi_truecolor_arg_get(ty, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*ptr) && (**ptr == ';'))
|
||||||
|
{
|
||||||
|
*ptr = (*ptr) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return _approximate_truecolor_rgb(ty, r0, g0, b0);
|
if (c == -CSI_ARG_NO_VALUE)
|
||||||
|
c = 0;
|
||||||
|
if (m == -CSI_ARG_NO_VALUE)
|
||||||
|
m = 0;
|
||||||
|
if (y == -CSI_ARG_NO_VALUE)
|
||||||
|
y = 0;
|
||||||
|
|
||||||
|
r = 255 - ((c * 255) / 100);
|
||||||
|
g = 255 - ((m * 255) / 100);
|
||||||
|
b = 255 - ((y * 255) / 100);
|
||||||
|
|
||||||
|
return _approximate_truecolor_rgb(ty, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_handle_esc_csi_truecolor_cmyk(Termpty *ty, Eina_Unicode **ptr)
|
_handle_esc_csi_truecolor_cmyk(Termpty *ty, Eina_Unicode **ptr)
|
||||||
{
|
{
|
||||||
int r0, g0, b0, c0, m0, y0, k0;
|
int r, g, b, c, m, y, k;
|
||||||
|
Eina_Unicode *u = *ptr;
|
||||||
|
char separator;
|
||||||
|
|
||||||
|
if ((u == NULL) || (*u == '\0'))
|
||||||
|
{
|
||||||
|
return COL_DEF;
|
||||||
|
}
|
||||||
|
separator = *(u-1);
|
||||||
|
|
||||||
/* Considering CMYK stored as percents */
|
/* Considering CMYK stored as percents */
|
||||||
c0 = _csi_truecolor_arg_get(ptr);
|
c = _csi_truecolor_arg_get(ty, ptr);
|
||||||
m0 = _csi_truecolor_arg_get(ptr);
|
m = _csi_truecolor_arg_get(ty, ptr);
|
||||||
y0 = _csi_truecolor_arg_get(ptr);
|
y = _csi_truecolor_arg_get(ty, ptr);
|
||||||
k0 = _csi_truecolor_arg_get(ptr);
|
k = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
|
||||||
if ((c0 < 0) || (m0 < 0) || (y0 < 0) || (k0 < 0))
|
if ((c == -CSI_ARG_ERROR) ||
|
||||||
|
(m == -CSI_ARG_ERROR) ||
|
||||||
|
(y == -CSI_ARG_ERROR) ||
|
||||||
|
(k == -CSI_ARG_ERROR))
|
||||||
return COL_DEF;
|
return COL_DEF;
|
||||||
|
|
||||||
c0 = c0 * (100 - k0) + k0;
|
if (separator == ':' && *ptr)
|
||||||
m0 = m0 * (100 - k0) + k0;
|
{
|
||||||
y0 = y0 * (100 - k0) + k0;
|
if (**ptr != ';')
|
||||||
|
{
|
||||||
|
/* then the first parameter was a color-space-id (ignored) */
|
||||||
|
c = m;
|
||||||
|
m = y;
|
||||||
|
y = k;
|
||||||
|
k = _csi_truecolor_arg_get(ty, ptr);
|
||||||
|
/* Skip other parameters */
|
||||||
|
while ((*ptr) && (**ptr != ';'))
|
||||||
|
{
|
||||||
|
_csi_truecolor_arg_get(ty, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*ptr) && (**ptr == ';'))
|
||||||
|
{
|
||||||
|
*ptr = (*ptr) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r0 = 255 - ((c0 * 255) / 100);
|
if (c == -CSI_ARG_NO_VALUE)
|
||||||
g0 = 255 - ((m0 * 255) / 100);
|
c = 0;
|
||||||
b0 = 255 - ((y0 * 255) / 100);
|
if (m == -CSI_ARG_NO_VALUE)
|
||||||
|
m = 0;
|
||||||
|
if (y == -CSI_ARG_NO_VALUE)
|
||||||
|
y = 0;
|
||||||
|
if (k == -CSI_ARG_NO_VALUE)
|
||||||
|
k = 0;
|
||||||
|
|
||||||
return _approximate_truecolor_rgb(ty, r0, g0, b0);
|
r = (255 * (100 - c) * (100 - k)) / 100 / 100;
|
||||||
|
g = (255 * (100 - m) * (100 - k)) / 100 / 100;
|
||||||
|
b = (255 * (100 - y) * (100 - k)) / 100 / 100;
|
||||||
|
|
||||||
|
return _approximate_truecolor_rgb(ty, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -715,7 +844,6 @@ _handle_esc_csi_color_set(Termpty *ty, Eina_Unicode **ptr,
|
||||||
{
|
{
|
||||||
case -CSI_ARG_ERROR:
|
case -CSI_ARG_ERROR:
|
||||||
return;
|
return;
|
||||||
/* TODO: -CSI_ARG_NO_VALUE */
|
|
||||||
case -CSI_ARG_NO_VALUE:
|
case -CSI_ARG_NO_VALUE:
|
||||||
EINA_FALLTHROUGH;
|
EINA_FALLTHROUGH;
|
||||||
case 0: // reset to normal
|
case 0: // reset to normal
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# pick 2 colors as RGB (orange for background, blue for foreground)
|
||||||
|
# compute the values for CMY and CMYK colorspaces
|
||||||
|
# Have 4 colums for each kind of format used in TrueColor escape codes
|
||||||
|
|
||||||
|
#BG-48: #f49019
|
||||||
|
# R:244 G:144 B:25
|
||||||
|
# C:4 M:43 Y:90
|
||||||
|
# C:0 M:41 Y:90 K:4
|
||||||
|
|
||||||
|
#FG-38: #3896c7
|
||||||
|
# R:56 G:150 B:199
|
||||||
|
# C:78 M:41 Y:22
|
||||||
|
# C:72 M:25 Y:0 K:22
|
||||||
|
|
||||||
|
|
||||||
|
# cursor to 0,0 and clear line
|
||||||
|
printf '\033[H\033[2K'
|
||||||
|
|
||||||
|
# formats for each columns
|
||||||
|
printf '\033[1;1H\033[0m38:2:n:n:nm'
|
||||||
|
printf '\033[1;13H\033[0m38:2:42:n:n:nm'
|
||||||
|
printf '\033[1;28H\033[0m38:2:42:n:n:n:4m'
|
||||||
|
printf '\033[1;45H\033[0m38;2;n;n;nm'
|
||||||
|
|
||||||
|
##
|
||||||
|
# RGB
|
||||||
|
##
|
||||||
|
printf '\033[3;1H\033[0;1;37mRGB'
|
||||||
|
|
||||||
|
# 1
|
||||||
|
printf '\033[4;1H\033[0;1;37m1'
|
||||||
|
printf '\033[48:2:244:144:25m'
|
||||||
|
printf '\033[38:2:56:150:199m'
|
||||||
|
printf '\033[4;5H▗▖'
|
||||||
|
printf '\033[5;5H▝▘'
|
||||||
|
|
||||||
|
# 2
|
||||||
|
printf '\033[4;13H\033[0;1;37m2'
|
||||||
|
printf '\033[48:2:42:244:144:25m'
|
||||||
|
printf '\033[38:2:42:56:150:199m'
|
||||||
|
printf '\033[4;17H▗▖'
|
||||||
|
printf '\033[5;17H▝▘'
|
||||||
|
|
||||||
|
# 3
|
||||||
|
printf '\033[4;28H\033[0;1;37m3'
|
||||||
|
printf '\033[48:2:42:244:144:25:4m'
|
||||||
|
printf '\033[38:2:42:56:150:199:4m'
|
||||||
|
printf '\033[4;32H▗▖'
|
||||||
|
printf '\033[5;32H▝▘'
|
||||||
|
|
||||||
|
# 4
|
||||||
|
printf '\033[4;45H\033[0;1;37m4'
|
||||||
|
printf '\033[48;2;244;144;25m'
|
||||||
|
printf '\033[38;2;56;150;199m'
|
||||||
|
printf '\033[4;49H▗▖'
|
||||||
|
printf '\033[5;49H▝▘'
|
||||||
|
|
||||||
|
# Same but on one sequence
|
||||||
|
printf '\033[6;1H\033[0mSame but fg+bg on one sequence'
|
||||||
|
|
||||||
|
#1
|
||||||
|
printf '\033[7;1H\033[0;1;37m1'
|
||||||
|
printf '\033[48:2:244:144:25;38:2:56:150:199m'
|
||||||
|
printf '\033[7;5H▗▖'
|
||||||
|
printf '\033[8;5H▝▘'
|
||||||
|
|
||||||
|
# 2
|
||||||
|
printf '\033[7;13H\033[0;1;37m2'
|
||||||
|
printf '\033[1;13H\033[0m38:2:42:n:n:nm'
|
||||||
|
printf '\033[48:2:42:244:144:25;38:2:42:56:150:199m'
|
||||||
|
printf '\033[7;17H▗▖'
|
||||||
|
printf '\033[8;17H▝▘'
|
||||||
|
|
||||||
|
# 3
|
||||||
|
printf '\033[7;28H\033[0;1;37m3'
|
||||||
|
printf '\033[48:2:42:244:144:25:4;38:2:42:56:150:199:4m'
|
||||||
|
printf '\033[7;32H▗▖'
|
||||||
|
printf '\033[8;32H▝▘'
|
||||||
|
|
||||||
|
# 4
|
||||||
|
printf '\033[7;45H\033[0;1;37m4'
|
||||||
|
printf '\033[48;2;244;144;25;38;2;56;150;199m'
|
||||||
|
printf '\033[7;49H▗▖'
|
||||||
|
printf '\033[8;49H▝▘'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# CMY
|
||||||
|
##
|
||||||
|
printf '\033[10;1H\033[0;1;37mCMY'
|
||||||
|
# 1
|
||||||
|
printf '\033[11;1H\033[0;1;37m1'
|
||||||
|
printf '\033[48:3:4:43:90m'
|
||||||
|
printf '\033[38:3:78:41:22m'
|
||||||
|
printf '\033[11;5H▗▖'
|
||||||
|
printf '\033[12;5H▝▘'
|
||||||
|
|
||||||
|
# 2
|
||||||
|
printf '\033[11;13H\033[0;1;37m2'
|
||||||
|
printf '\033[48:3:42:4:43:90m'
|
||||||
|
printf '\033[38:3:42:78:41:22m'
|
||||||
|
printf '\033[11;17H▗▖'
|
||||||
|
printf '\033[12;17H▝▘'
|
||||||
|
|
||||||
|
# 3
|
||||||
|
printf '\033[11;28H\033[0;1;37m3'
|
||||||
|
printf '\033[48:3:42:4:43:90:4m'
|
||||||
|
printf '\033[38:3:42:78:41:22:4m'
|
||||||
|
printf '\033[11;32H▗▖'
|
||||||
|
printf '\033[12;32H▝▘'
|
||||||
|
|
||||||
|
# 4
|
||||||
|
printf '\033[11;45H\033[0;1;37m4'
|
||||||
|
printf '\033[48;3;4;43;90m'
|
||||||
|
printf '\033[38;3;78;41;22m'
|
||||||
|
printf '\033[11;49H▗▖'
|
||||||
|
printf '\033[12;49H▝▘'
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
# CMYK
|
||||||
|
##
|
||||||
|
printf '\033[14;1H\033[0;1;37mCMYK'
|
||||||
|
# 1
|
||||||
|
printf '\033[15;1H\033[0;1;37m1'
|
||||||
|
printf '\033[48:4::0:41:90:4m'
|
||||||
|
printf '\033[38:4::72:25:0:22m'
|
||||||
|
printf '\033[15;5H▗▖'
|
||||||
|
printf '\033[16;5H▝▘'
|
||||||
|
|
||||||
|
# 2
|
||||||
|
printf '\033[15;13H\033[0;1;37m2'
|
||||||
|
printf '\033[48:4:42:0:41:90:4m'
|
||||||
|
printf '\033[38:4:42:72:25:0:22m'
|
||||||
|
printf '\033[15;17H▗▖'
|
||||||
|
printf '\033[16;17H▝▘'
|
||||||
|
|
||||||
|
# 3
|
||||||
|
printf '\033[15;28H\033[0;1;37m3'
|
||||||
|
printf '\033[48:4:42:0:41:90:4:4m'
|
||||||
|
printf '\033[38:4:42:72:25:0:22:4m'
|
||||||
|
printf '\033[15;32H▗▖'
|
||||||
|
printf '\033[16;32H▝▘'
|
||||||
|
|
||||||
|
# 4
|
||||||
|
printf '\033[15;45H\033[0;1;37m4'
|
||||||
|
printf '\033[48;4;0;41;90;4m'
|
||||||
|
printf '\033[38;4;72;25;0;22m'
|
||||||
|
printf '\033[15;49H▗▖'
|
||||||
|
printf '\033[16;49H▝▘'
|
|
@ -27,3 +27,4 @@ dsr-pp.sh 0f0a7d5beccefbad4f4984fc4611276e
|
||||||
dsr-udk.sh f3a20968a2f25bfd36875dbc5f64ab16
|
dsr-udk.sh f3a20968a2f25bfd36875dbc5f64ab16
|
||||||
colors.sh 532494a2e56c102ee10ab1a9b8f176d7
|
colors.sh 532494a2e56c102ee10ab1a9b8f176d7
|
||||||
sgr-leading-trailing-semicolon.sh d7701f1193bde63412a9b969f17e10ec
|
sgr-leading-trailing-semicolon.sh d7701f1193bde63412a9b969f17e10ec
|
||||||
|
sgr-truecolors.sh 9db4becc728bb9f1730f3573dc7fc668
|
||||||
|
|
Loading…
Reference in New Issue