Implement SGR dim

kitty now supports the SGR DIM escape code, which makes text fade into
the background. It works by alpha blending the text color into the
background color. Fixes #446
This commit is contained in:
Kovid Goyal
2018-05-20 10:43:26 +05:30
parent 9cab8a2de5
commit 6f2d63eb87
11 changed files with 54 additions and 32 deletions

View File

@@ -19,7 +19,7 @@ in float bg_alpha;
#ifdef NEEDS_FOREGROUND #ifdef NEEDS_FOREGROUND
uniform sampler2DArray sprites; uniform sampler2DArray sprites;
uniform float inactive_text_alpha; in float effective_text_alpha;
in vec3 sprite_pos; in vec3 sprite_pos;
in vec3 underline_pos; in vec3 underline_pos;
in vec3 strike_pos; in vec3 strike_pos;
@@ -61,7 +61,7 @@ vec4 calculate_foreground() {
// Since strike and text are the same color, we simply add the alpha values // Since strike and text are the same color, we simply add the alpha values
float combined_alpha = min(text_alpha + strike_alpha, 1.0f); float combined_alpha = min(text_alpha + strike_alpha, 1.0f);
// Underline color might be different, so alpha blend // Underline color might be different, so alpha blend
return alpha_blend(decoration_fg, underline_alpha * inactive_text_alpha, fg, combined_alpha * inactive_text_alpha); return alpha_blend(decoration_fg, underline_alpha * effective_text_alpha, fg, combined_alpha * effective_text_alpha);
} }
#endif #endif

View File

@@ -1,6 +1,7 @@
#version GLSL_VERSION #version GLSL_VERSION
#define WHICH_PROGRAM #define WHICH_PROGRAM
#define NOT_TRANSPARENT #define NOT_TRANSPARENT
#define SHIFTS
// Inputs {{{ // Inputs {{{
layout(std140) uniform CellRenderData { layout(std140) uniform CellRenderData {
@@ -45,12 +46,14 @@ out float bg_alpha;
#endif #endif
#ifdef NEEDS_FOREGROUND #ifdef NEEDS_FOREGROUND
uniform float inactive_text_alpha;
out vec3 sprite_pos; out vec3 sprite_pos;
out vec3 underline_pos; out vec3 underline_pos;
out vec3 strike_pos; out vec3 strike_pos;
out vec3 foreground; out vec3 foreground;
out vec3 decoration_fg; out vec3 decoration_fg;
out float colored_sprite; out float colored_sprite;
out float effective_text_alpha;
#endif #endif
@@ -63,9 +66,6 @@ const uint ONE = uint(1);
const uint TWO = uint(2); const uint TWO = uint(2);
const uint THREE = uint(3); const uint THREE = uint(3);
const uint FOUR = uint(4); const uint FOUR = uint(4);
const uint DECORATION_MASK = uint(3);
const uint STRIKE_MASK = uint(1);
const uint REVERSE_MASK = uint(1);
vec3 color_to_vec(uint c) { vec3 color_to_vec(uint c) {
uint r, g, b; uint r, g, b;
@@ -134,7 +134,7 @@ void main() {
// set cell color indices {{{ // set cell color indices {{{
uvec2 default_colors = uvec2(default_fg, default_bg); uvec2 default_colors = uvec2(default_fg, default_bg);
uint text_attrs = sprite_coords[3]; uint text_attrs = sprite_coords[3];
uint is_inverted = ((text_attrs >> 6) & REVERSE_MASK) + inverted; uint is_inverted = ((text_attrs >> REVERSE_SHIFT) & ONE) + inverted;
int fg_index = fg_index_map[is_inverted]; int fg_index = fg_index_map[is_inverted];
int bg_index = 1 - fg_index; int bg_index = 1 - fg_index;
float cursor = is_cursor(c, r); float cursor = is_cursor(c, r);
@@ -151,13 +151,15 @@ void main() {
// Foreground // Foreground
uint resolved_fg = resolve_color(colors[fg_index], default_colors[fg_index]); uint resolved_fg = resolve_color(colors[fg_index], default_colors[fg_index]);
foreground = color_to_vec(resolved_fg); foreground = color_to_vec(resolved_fg);
float has_dim = float((text_attrs >> DIM_SHIFT) & ONE);
effective_text_alpha = inactive_text_alpha * mix(1.0, 0.75, has_dim);
// Selection // Selection
foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground); foreground = choose_color(float(is_selected & ONE), color_to_vec(highlight_fg), foreground);
// Underline and strike through (rendered via sprites) // Underline and strike through (rendered via sprites)
float in_url = float((is_selected & TWO) >> 1); float in_url = float((is_selected & TWO) >> 1);
decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg)); decoration_fg = choose_color(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO)); underline_pos = choose_color(in_url, to_sprite_pos(pos, url_style, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> DECORATION_SHIFT) & THREE, ZERO, ZERO));
strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * FOUR, ZERO, ZERO); strike_pos = to_sprite_pos(pos, ((text_attrs >> STRIKE_SHIFT) & ONE) * FOUR, ZERO, ZERO);
// Cursor // Cursor
foreground = choose_color(cursor, bg, foreground); foreground = choose_color(cursor, bg, foreground);

View File

@@ -24,7 +24,7 @@ dealloc(Cursor* self) {
#define EQ(x) (a->x == b->x) #define EQ(x) (a->x == b->x)
static int __eq__(Cursor *a, Cursor *b) { static int __eq__(Cursor *a, Cursor *b) {
return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && EQ(x) && EQ(y) && EQ(shape) && EQ(blink); return EQ(bold) && EQ(italic) && EQ(strikethrough) && EQ(dim) && EQ(reverse) && EQ(decoration) && EQ(fg) && EQ(bg) && EQ(decoration_fg) && EQ(x) && EQ(y) && EQ(shape) && EQ(blink);
} }
static const char* cursor_names[NUM_OF_CURSOR_SHAPES] = { "NO_SHAPE", "BLOCK", "BEAM", "UNDERLINE" }; static const char* cursor_names[NUM_OF_CURSOR_SHAPES] = { "NO_SHAPE", "BLOCK", "BEAM", "UNDERLINE" };
@@ -33,16 +33,16 @@ static const char* cursor_names[NUM_OF_CURSOR_SHAPES] = { "NO_SHAPE", "BLOCK", "
static PyObject * static PyObject *
repr(Cursor *self) { repr(Cursor *self) {
return PyUnicode_FromFormat( return PyUnicode_FromFormat(
"Cursor(x=%u, y=%u, shape=%s, blink=%R, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, decoration=%d, decoration_fg=#%08x)", "Cursor(x=%u, y=%u, shape=%s, blink=%R, fg=#%08x, bg=#%08x, bold=%R, italic=%R, reverse=%R, strikethrough=%R, dim=%R, decoration=%d, decoration_fg=#%08x)",
self->x, self->y, (self->shape < NUM_OF_CURSOR_SHAPES ? cursor_names[self->shape] : "INVALID"), self->x, self->y, (self->shape < NUM_OF_CURSOR_SHAPES ? cursor_names[self->shape] : "INVALID"),
BOOL(self->blink), self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), self->decoration, self->decoration_fg BOOL(self->blink), self->fg, self->bg, BOOL(self->bold), BOOL(self->italic), BOOL(self->reverse), BOOL(self->strikethrough), BOOL(self->dim), self->decoration, self->decoration_fg
); );
} }
void void
cursor_reset_display_attrs(Cursor *self) { cursor_reset_display_attrs(Cursor *self) {
self->bg = 0; self->fg = 0; self->decoration_fg = 0; self->bg = 0; self->fg = 0; self->decoration_fg = 0;
self->decoration = 0; self->bold = false; self->italic = false; self->reverse = false; self->strikethrough = false; self->decoration = 0; self->bold = false; self->italic = false; self->reverse = false; self->strikethrough = false; self->dim = false;
} }
@@ -85,6 +85,8 @@ START_ALLOW_CASE_RANGE
cursor_reset_display_attrs(self); break; cursor_reset_display_attrs(self); break;
case 1: case 1:
self->bold = true; break; self->bold = true; break;
case 2:
self->dim = true; break;
case 3: case 3:
self->italic = true; break; self->italic = true; break;
case 4: case 4:
@@ -98,7 +100,7 @@ START_ALLOW_CASE_RANGE
case 21: case 21:
self->decoration = 2; break; self->decoration = 2; break;
case 22: case 22:
self->bold = false; break; self->bold = false; self->dim = false; break;
case 23: case 23:
self->italic = false; break; self->italic = false; break;
case 24: case 24:
@@ -138,6 +140,7 @@ apply_sgr_to_cells(Cell *first_cell, unsigned int cell_count, unsigned int *para
#define RANGE for(unsigned c = 0; c < cell_count; c++, cell++) #define RANGE for(unsigned c = 0; c < cell_count; c++, cell++)
#define SET(shift) RANGE { cell->attrs |= (1 << shift); } break; #define SET(shift) RANGE { cell->attrs |= (1 << shift); } break;
#define RESET(shift) RANGE { cell->attrs &= ~(1 << shift); } break; #define RESET(shift) RANGE { cell->attrs &= ~(1 << shift); } break;
#define RESET2(shift1, shift2) RANGE { cell->attrs &= ~((1 << shift1) | (1 << shift2)); } break;
#define SETM(val, mask, shift) { RANGE { cell->attrs &= ~(mask << shift); cell->attrs |= ((val) << shift); } break; } #define SETM(val, mask, shift) { RANGE { cell->attrs &= ~(mask << shift); cell->attrs |= ((val) << shift); } break; }
#define SET_COLOR(which) { color_type color = 0; parse_color(params, &i, count, &color); if (color) { RANGE { cell->which = color; }} } break; #define SET_COLOR(which) { color_type color = 0; parse_color(params, &i, count, &color); if (color) { RANGE { cell->which = color; }} } break;
#define SIMPLE(which, val) RANGE { cell->which = (val); } break; #define SIMPLE(which, val) RANGE { cell->which = (val); } break;
@@ -153,6 +156,8 @@ apply_sgr_to_cells(Cell *first_cell, unsigned int cell_count, unsigned int *para
break; break;
case 1: case 1:
SET(BOLD_SHIFT); SET(BOLD_SHIFT);
case 2:
SET(DIM_SHIFT);
case 3: case 3:
SET(ITALIC_SHIFT); SET(ITALIC_SHIFT);
case 4: case 4:
@@ -165,7 +170,7 @@ apply_sgr_to_cells(Cell *first_cell, unsigned int cell_count, unsigned int *para
case 21: case 21:
SETM(2, DECORATION_MASK, DECORATION_SHIFT); SETM(2, DECORATION_MASK, DECORATION_SHIFT);
case 22: case 22:
RESET(BOLD_SHIFT); RESET2(DIM_SHIFT, BOLD_SHIFT);
case 23: case 23:
RESET(ITALIC_SHIFT); RESET(ITALIC_SHIFT);
case 24: case 24:
@@ -199,6 +204,7 @@ END_ALLOW_CASE_RANGE
} }
} }
#undef RESET #undef RESET
#undef RESET2
#undef SET_COLOR #undef SET_COLOR
#undef SET #undef SET
#undef SETM #undef SETM
@@ -237,7 +243,11 @@ cursor_as_sgr(Cursor *self, Cursor *prev) {
#define SZ sizeof(buf) - (p - buf) - 2 #define SZ sizeof(buf) - (p - buf) - 2
#define P(fmt, ...) { p += snprintf(p, SZ, fmt ";", __VA_ARGS__); } #define P(fmt, ...) { p += snprintf(p, SZ, fmt ";", __VA_ARGS__); }
char *p = buf; char *p = buf;
if (self->bold != prev->bold) P("%d", self->bold ? 1 : 22); bool intensity_differs = self->bold != prev->bold || self->dim != prev->dim;
if (intensity_differs) {
if (!self->bold || !self->dim) { P("%d", 22); }
else P("%d;%d", 1, 2);
}
if (self->italic != prev->italic) P("%d", self->italic ? 3 : 23); if (self->italic != prev->italic) P("%d", self->italic ? 3 : 23);
if (self->reverse != prev->reverse) P("%d", self->reverse ? 7 : 27); if (self->reverse != prev->reverse) P("%d", self->reverse ? 7 : 27);
if (self->strikethrough != prev->strikethrough) P("%d", self->strikethrough ? 9 : 29); if (self->strikethrough != prev->strikethrough) P("%d", self->strikethrough ? 9 : 29);
@@ -268,7 +278,7 @@ void cursor_reset(Cursor *self) {
void cursor_copy_to(Cursor *src, Cursor *dest) { void cursor_copy_to(Cursor *src, Cursor *dest) {
#define CCY(x) dest->x = src->x; #define CCY(x) dest->x = src->x;
CCY(x); CCY(y); CCY(shape); CCY(blink); CCY(x); CCY(y); CCY(shape); CCY(blink);
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg); CCY(bold); CCY(italic); CCY(strikethrough); CCY(dim); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
} }
static PyObject* static PyObject*
@@ -281,6 +291,7 @@ BOOL_GETSET(Cursor, bold)
BOOL_GETSET(Cursor, italic) BOOL_GETSET(Cursor, italic)
BOOL_GETSET(Cursor, reverse) BOOL_GETSET(Cursor, reverse)
BOOL_GETSET(Cursor, strikethrough) BOOL_GETSET(Cursor, strikethrough)
BOOL_GETSET(Cursor, dim)
BOOL_GETSET(Cursor, blink) BOOL_GETSET(Cursor, blink)
static PyMemberDef members[] = { static PyMemberDef members[] = {
@@ -299,6 +310,7 @@ static PyGetSetDef getseters[] = {
GETSET(italic) GETSET(italic)
GETSET(reverse) GETSET(reverse)
GETSET(strikethrough) GETSET(strikethrough)
GETSET(dim)
GETSET(blink) GETSET(blink)
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };

View File

@@ -197,6 +197,7 @@ PyInit_fast_data_types(void) {
PyModule_AddIntConstant(m, "ITALIC", ITALIC_SHIFT); PyModule_AddIntConstant(m, "ITALIC", ITALIC_SHIFT);
PyModule_AddIntConstant(m, "REVERSE", REVERSE_SHIFT); PyModule_AddIntConstant(m, "REVERSE", REVERSE_SHIFT);
PyModule_AddIntConstant(m, "STRIKETHROUGH", STRIKE_SHIFT); PyModule_AddIntConstant(m, "STRIKETHROUGH", STRIKE_SHIFT);
PyModule_AddIntConstant(m, "DIM", DIM_SHIFT);
PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT); PyModule_AddIntConstant(m, "DECORATION", DECORATION_SHIFT);
PyModule_AddStringMacro(m, ERROR_PREFIX); PyModule_AddStringMacro(m, ERROR_PREFIX);
#ifdef KITTY_VCS_REV #ifdef KITTY_VCS_REV

View File

@@ -58,6 +58,7 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
#define BI_VAL(attrs) ((attrs >> 4) & 3) #define BI_VAL(attrs) ((attrs >> 4) & 3)
#define REVERSE_SHIFT 6 #define REVERSE_SHIFT 6
#define STRIKE_SHIFT 7 #define STRIKE_SHIFT 7
#define DIM_SHIFT 8
#define COL_MASK 0xFFFFFFFF #define COL_MASK 0xFFFFFFFF
#define UTF8_ACCEPT 0 #define UTF8_ACCEPT 0
#define UTF8_REJECT 1 #define UTF8_REJECT 1
@@ -71,11 +72,12 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
#define CURSOR_TO_ATTRS(c, w) \ #define CURSOR_TO_ATTRS(c, w) \
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \ ((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT))) ((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | \
((c->strikethrough & 1) << STRIKE_SHIFT) | ((c->dim & 1) << DIM_SHIFT)))
#define ATTRS_TO_CURSOR(a, c) \ #define ATTRS_TO_CURSOR(a, c) \
(c)->decoration = (a >> DECORATION_SHIFT) & 3; (c)->bold = (a >> BOLD_SHIFT) & 1; (c)->italic = (a >> ITALIC_SHIFT) & 1; \ (c)->decoration = (a >> DECORATION_SHIFT) & 3; (c)->bold = (a >> BOLD_SHIFT) & 1; (c)->italic = (a >> ITALIC_SHIFT) & 1; \
(c)->reverse = (a >> REVERSE_SHIFT) & 1; (c)->strikethrough = (a >> STRIKE_SHIFT) & 1; (c)->reverse = (a >> REVERSE_SHIFT) & 1; (c)->strikethrough = (a >> STRIKE_SHIFT) & 1; (c)->dim = (a >> DIM_SHIFT) & 1;
#define COPY_CELL(src, s, dest, d) \ #define COPY_CELL(src, s, dest, d) \
(dest)->cells[d] = (src)->cells[s]; (dest)->cells[d] = (src)->cells[s];
@@ -178,7 +180,7 @@ typedef struct {
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
bool bold, italic, reverse, strikethrough, blink; bool bold, italic, reverse, strikethrough, blink, dim;
unsigned int x, y; unsigned int x, y;
uint8_t decoration; uint8_t decoration;
CursorShape shape; CursorShape shape;

View File

@@ -149,7 +149,7 @@ set_attribute(LineBuf *self, PyObject *args) {
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line." #define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
unsigned int shift, val; unsigned int shift, val;
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL; if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
if (shift < DECORATION_SHIFT || shift > STRIKE_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; } if (shift < DECORATION_SHIFT || shift > DIM_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; }
linebuf_set_attribute(self, shift, val); linebuf_set_attribute(self, shift, val);
Py_RETURN_NONE; Py_RETURN_NONE;
} }

View File

@@ -515,7 +515,7 @@ set_attribute(Line *self, PyObject *args) {
#define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line." #define set_attribute_doc "set_attribute(which, val) -> Set the attribute on all cells in the line."
unsigned int shift, val; unsigned int shift, val;
if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL; if (!PyArg_ParseTuple(args, "II", &shift, &val)) return NULL;
if (shift < DECORATION_SHIFT || shift > STRIKE_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; } if (shift < DECORATION_SHIFT || shift > DIM_SHIFT) { PyErr_SetString(PyExc_ValueError, "Unknown attribute"); return NULL; }
set_attribute_on_line(self->cells, shift, val, self->xnum); set_attribute_on_line(self->cells, shift, val, self->xnum);
Py_RETURN_NONE; Py_RETURN_NONE;
} }

View File

@@ -15,9 +15,10 @@ from .constants import (
) )
from .fast_data_types import ( from .fast_data_types import (
BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM,
CELL_SPECIAL_PROGRAM, CSI, CURSOR_PROGRAM, DCS, GRAPHICS_PREMULT_PROGRAM, CELL_SPECIAL_PROGRAM, CSI, CURSOR_PROGRAM, DCS, DECORATION, DIM,
GRAPHICS_PROGRAM, OSC, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, GRAPHICS_PREMULT_PROGRAM, GRAPHICS_PROGRAM, OSC, REVERSE, SCROLL_FULL,
add_window, compile_program, get_clipboard_string, glfw_post_empty_event, SCROLL_LINE, SCROLL_PAGE, STRIKETHROUGH, Screen, add_window,
compile_program, get_clipboard_string, glfw_post_empty_event,
init_cell_program, init_cursor_program, set_clipboard_string, init_cell_program, init_cursor_program, set_clipboard_string,
set_titlebar_color, set_window_render_data, update_window_title, set_titlebar_color, set_window_render_data, update_window_title,
update_window_visibility, viewport_for_window update_window_visibility, viewport_for_window
@@ -64,6 +65,10 @@ def load_shader_programs(semi_transparent=0):
'FOREGROUND': CELL_FG_PROGRAM, 'FOREGROUND': CELL_FG_PROGRAM,
}.items(): }.items():
vv, ff = v.replace('WHICH_PROGRAM', which), f.replace('WHICH_PROGRAM', which) vv, ff = v.replace('WHICH_PROGRAM', which), f.replace('WHICH_PROGRAM', which)
shifts = '\n'.join('#define {} {}'.format(name, val) for name, val in (
('DECORATION_SHIFT', DECORATION), ('REVERSE_SHIFT', REVERSE), ('STRIKE_SHIFT', STRIKETHROUGH), ('DIM_SHIFT', DIM),
))
vv = vv.replace('#define SHIFTS', shifts)
if semi_transparent: if semi_transparent:
vv = vv.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT') vv = vv.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')
ff = ff.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT') ff = ff.replace('#define NOT_TRANSPARENT', '#define TRANSPARENT')

View File

@@ -52,7 +52,7 @@ def filled_line_buf(ynum=5, xnum=5, cursor=Cursor()):
def filled_cursor(): def filled_cursor():
ans = Cursor() ans = Cursor()
ans.bold = ans.italic = ans.reverse = ans.strikethrough = True ans.bold = ans.italic = ans.reverse = ans.strikethrough = ans.dim = True
ans.fg = 0x101 ans.fg = 0x101
ans.bg = 0x201 ans.bg = 0x201
ans.decoration_fg = 0x301 ans.decoration_fg = 0x301

View File

@@ -179,7 +179,7 @@ class TestDataTypes(BaseTest):
self.assertEqual(str(l0), 'a' + t[1:]) self.assertEqual(str(l0), 'a' + t[1:])
c = C(3, 5) c = C(3, 5)
c.bold = c.italic = c.reverse = c.strikethrough = True c.bold = c.italic = c.reverse = c.strikethrough = c.dim = True
c.fg = c.bg = c.decoration_fg = 0x0101 c.fg = c.bg = c.decoration_fg = 0x0101
self.ae(c, c) self.ae(c, c)
c2, c3 = c.copy(), c.copy() c2, c3 = c.copy(), c.copy()
@@ -219,7 +219,7 @@ class TestDataTypes(BaseTest):
l3.set_text(t, 0, len(t), C()) l3.set_text(t, 0, len(t), C())
q = C() q = C()
q.bold = q.italic = q.reverse = q.strikethrough = True q.bold = q.italic = q.reverse = q.strikethrough = c.dim = True
q.decoration = 2 q.decoration = 2
c = C() c = C()
c.x = 3 c.x = 3
@@ -450,12 +450,12 @@ class TestDataTypes(BaseTest):
self.ae(a, ['\x1b[0m' + str(lb.line(i)) + '\n' for i in range(lb.ynum)]) self.ae(a, ['\x1b[0m' + str(lb.line(i)) + '\n' for i in range(lb.ynum)])
l2 = lb.line(0) l2 = lb.line(0)
c = C() c = C()
c.bold = c.italic = c.reverse = c.strikethrough = True c.bold = c.italic = c.reverse = c.strikethrough = c.dim = True
c.fg = (4 << 8) | 1 c.fg = (4 << 8) | 1
c.bg = (1 << 24) | (2 << 16) | (3 << 8) | 2 c.bg = (1 << 24) | (2 << 16) | (3 << 8) | 2
c.decoration_fg = (5 << 8) | 1 c.decoration_fg = (5 << 8) | 1
l2.set_text('1', 0, 1, c) l2.set_text('1', 0, 1, c)
self.ae(l2.as_ansi(), '\x1b[0m\x1b[1;3;7;9;34;48:2:1:2:3;58:5:5m' '1' self.ae(l2.as_ansi(), '\x1b[0m\x1b[1;2;3;7;9;34;48:2:1:2:3;58:5:5m' '1'
'\x1b[22;23;27;29;39;49;59m' '0000') '\x1b[22;23;27;29;39;49;59m' '0000')
lb = filled_line_buf() lb = filled_line_buf()
for i in range(lb.ynum): for i in range(lb.ynum):

View File

@@ -118,8 +118,8 @@ class TestParser(BaseTest):
def sgr(params): def sgr(params):
return (('select_graphic_rendition', '{} '.format(x)) for x in params.split()) return (('select_graphic_rendition', '{} '.format(x)) for x in params.split())
pb('\033[1;3;4;7;9;34;44m', *sgr('1 3 4 7 9 34 44')) pb('\033[1;2;3;4;7;9;34;44m', *sgr('1 2 3 4 7 9 34 44'))
for attr in 'bold italic reverse strikethrough'.split(): for attr in 'bold italic reverse strikethrough dim'.split():
self.assertTrue(getattr(s.cursor, attr)) self.assertTrue(getattr(s.cursor, attr))
self.ae(s.cursor.decoration, 1) self.ae(s.cursor.decoration, 1)
self.ae(s.cursor.fg, 4 << 8 | 1) self.ae(s.cursor.fg, 4 << 8 | 1)
@@ -202,7 +202,7 @@ class TestParser(BaseTest):
c.clear() c.clear()
pb('\033P$qm\033\\', ('screen_request_capabilities', ord('$'), 'm')) pb('\033P$qm\033\\', ('screen_request_capabilities', ord('$'), 'm'))
self.ae(c.wtcbuf, b'\033P1$rm\033\\') self.ae(c.wtcbuf, b'\033P1$rm\033\\')
for sgr in '0;34;102;1;3;4 0;38:5:200;58:2:10:11:12'.split(): for sgr in '0;34;102;1;2;3;4 0;38:5:200;58:2:10:11:12'.split():
expected = set(sgr.split(';')) - {'0'} expected = set(sgr.split(';')) - {'0'}
c.clear() c.clear()
parse_bytes(s, '\033[{}m\033P$qm\033\\'.format(sgr).encode('ascii')) parse_bytes(s, '\033[{}m\033P$qm\033\\'.format(sgr).encode('ascii'))