mirror of
https://github.com/kovidgoyal/kitty.git
synced 2025-12-13 20:36:22 +01:00
Implement round tripping of SGR blink (5/25)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#define REVERSE_SHIFT {REVERSE_SHIFT}
|
||||
#define STRIKE_SHIFT {STRIKE_SHIFT}
|
||||
#define DIM_SHIFT {DIM_SHIFT}
|
||||
#define BLINK_SHIFT {BLINK_SHIFT}
|
||||
#define MARK_SHIFT {MARK_SHIFT}
|
||||
#define MARK_MASK {MARK_MASK}
|
||||
#define USE_SELECTION_FG
|
||||
|
||||
@@ -34,9 +34,9 @@ static const char* cursor_names[NUM_OF_CURSOR_SHAPES] = { "NO_SHAPE", "BLOCK", "
|
||||
static PyObject *
|
||||
repr(Cursor *self) {
|
||||
return PyUnicode_FromFormat(
|
||||
"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)",
|
||||
"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, text_blink=%R)",
|
||||
self->x, self->y, (self->shape < NUM_OF_CURSOR_SHAPES ? cursor_names[self->shape] : "INVALID"),
|
||||
BOOL(!self->non_blinking), self->sgr.fg, self->sgr.bg, BOOL(self->sgr.bold), BOOL(self->sgr.italic), BOOL(self->sgr.reverse), BOOL(self->sgr.strikethrough), BOOL(self->sgr.dim), self->sgr.decoration, self->sgr.decoration_fg
|
||||
BOOL(!self->non_blinking), self->sgr.fg, self->sgr.bg, BOOL(self->sgr.bold), BOOL(self->sgr.italic), BOOL(self->sgr.reverse), BOOL(self->sgr.strikethrough), BOOL(self->sgr.dim), self->sgr.decoration, self->sgr.decoration_fg, BOOL(self->sgr.blink)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ START_ALLOW_CASE_RANGE
|
||||
if (is_group && i < count) { self->sgr.decoration = MIN(5, params[i]); i++; }
|
||||
else self->sgr.decoration = 1;
|
||||
break;
|
||||
case 5:
|
||||
self->sgr.blink = true; break;
|
||||
case 7:
|
||||
self->sgr.reverse = true; break;
|
||||
case 9:
|
||||
@@ -109,6 +111,8 @@ START_ALLOW_CASE_RANGE
|
||||
self->sgr.italic = false; break;
|
||||
case 24:
|
||||
self->sgr.decoration = 0; break;
|
||||
case 25:
|
||||
self->sgr.blink = false; break;
|
||||
case 27:
|
||||
self->sgr.reverse = false; break;
|
||||
case 29:
|
||||
@@ -169,6 +173,8 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, un
|
||||
if (is_group && i < count) { val = MIN(5, params[i]); i++; }
|
||||
S(decoration, val);
|
||||
}
|
||||
case 5:
|
||||
S(blink, true);
|
||||
case 7:
|
||||
S(reverse, true);
|
||||
case 9:
|
||||
@@ -185,6 +191,8 @@ apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, un
|
||||
S(italic, false);
|
||||
case 24:
|
||||
S(decoration, 0);
|
||||
case 25:
|
||||
S(blink, false);
|
||||
case 27:
|
||||
S(reverse, false);
|
||||
case 29:
|
||||
@@ -272,6 +280,11 @@ static PyObject* blink_get(Cursor *self, void UNUSED *closure) { PyObject *ans =
|
||||
|
||||
static int blink_set(Cursor *self, PyObject *value, void UNUSED *closure) { if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } self->non_blinking = PyObject_IsTrue(value) ? false : true; return 0; }
|
||||
|
||||
static PyObject* text_blink_get(Cursor *self, void UNUSED *closure) { return Py_NewRef(self->sgr.blink ? Py_True : Py_False); }
|
||||
|
||||
static int text_blink_set(Cursor *self, PyObject *value, void UNUSED *closure) { if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } self->sgr.blink = PyObject_IsTrue(value) ? false : true; return 0; }
|
||||
|
||||
|
||||
#define SGR_UINT_GETSET(x) \
|
||||
static PyObject* x##_get(Cursor *self, void UNUSED *closure) { return PyLong_FromUnsignedLong((unsigned long)self->sgr.x); } \
|
||||
static int x##_set(Cursor *self, PyObject *value, void UNUSED *closure) { if (value == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } if (!PyLong_Check(value)) { PyErr_SetString(PyExc_TypeError, "value must be an int"); return -1; } self->sgr.x = PyLong_AsUnsignedLong(value); return 0; }
|
||||
@@ -295,6 +308,7 @@ static PyGetSetDef getseters[] = {
|
||||
GETSET(strikethrough)
|
||||
GETSET(dim)
|
||||
GETSET(blink)
|
||||
GETSET(text_blink)
|
||||
GETSET(decoration)
|
||||
GETSET(fg)
|
||||
GETSET(bg)
|
||||
|
||||
@@ -836,7 +836,7 @@ PyInit_fast_data_types(void) {
|
||||
CellAttrs a;
|
||||
#define s(name, attr) { a.val = 0; a.attr = 1; PyModule_AddIntConstant(m, #name, shift_to_first_set_bit(a)); }
|
||||
s(BOLD, bold); s(ITALIC, italic); s(REVERSE, reverse); s(MARK, mark);
|
||||
s(STRIKETHROUGH, strike); s(DIM, dim); s(DECORATION, decoration);
|
||||
s(STRIKETHROUGH, strike); s(DIM, dim); s(DECORATION, decoration); s(BLINK, blink);
|
||||
#undef s
|
||||
PyModule_AddIntConstant(m, "MARK_MASK", MARK_MASK);
|
||||
PyModule_AddIntConstant(m, "DECORATION_MASK", DECORATION_MASK);
|
||||
|
||||
@@ -217,7 +217,7 @@ typedef struct {
|
||||
CursorShape shape;
|
||||
|
||||
struct {
|
||||
bool bold, italic, reverse, strikethrough, dim;
|
||||
bool bold, italic, reverse, strikethrough, dim, blink;
|
||||
uint8_t decoration;
|
||||
color_type fg, bg, decoration_fg;
|
||||
} sgr;
|
||||
|
||||
@@ -277,6 +277,7 @@ CELL_BG_PROGRAM: int
|
||||
BLIT_PROGRAM: int
|
||||
ROUNDED_RECT_PROGRAM: int
|
||||
DECORATION: int
|
||||
BLINK: int
|
||||
DIM: int
|
||||
GRAPHICS_ALPHA_MASK_PROGRAM: int
|
||||
GRAPHICS_PROGRAM: int
|
||||
@@ -1195,6 +1196,7 @@ class Cursor:
|
||||
bold: bool
|
||||
italic: bool
|
||||
blink: bool
|
||||
text_blink: bool
|
||||
shape: int
|
||||
|
||||
|
||||
|
||||
@@ -920,6 +920,7 @@ cell_as_sgr(const GPUCell *cell, const GPUCell *prev) {
|
||||
if (CA.italic != PA.italic) P(CA.italic ? "3;" : "23;");
|
||||
if (CA.reverse != PA.reverse) P(CA.reverse ? "7;" : "27;");
|
||||
if (CA.strike != PA.strike) P(CA.strike ? "9;" : "29;");
|
||||
if (CA.blink != PA.blink) P(CA.blink ? "5;" : "25;");
|
||||
if (cell->fg != prev->fg) p += color_as_sgr(p, SZ, cell->fg, 30, 90, 38);
|
||||
if (cell->bg != prev->bg) p += color_as_sgr(p, SZ, cell->bg, 40, 100, 48);
|
||||
if (cell->decoration_fg != prev->decoration_fg) p += color_as_sgr(p, SZ, cell->decoration_fg, 0, 0, DECORATION_FG_CODE);
|
||||
|
||||
@@ -17,8 +17,9 @@ typedef union CellAttrs {
|
||||
uint16_t reverse : 1;
|
||||
uint16_t strike : 1;
|
||||
uint16_t dim : 1;
|
||||
uint16_t blink: 1;
|
||||
uint16_t mark : 2;
|
||||
uint32_t : 22;
|
||||
uint32_t : 21;
|
||||
};
|
||||
uint32_t val;
|
||||
} CellAttrs;
|
||||
@@ -180,7 +181,7 @@ static inline CellAttrs
|
||||
cursor_to_attrs(const Cursor *c) {
|
||||
CellAttrs ans = {
|
||||
.decoration=c->sgr.decoration, .bold=c->sgr.bold, .italic=c->sgr.italic, .reverse=c->sgr.reverse,
|
||||
.strike=c->sgr.strikethrough, .dim=c->sgr.dim};
|
||||
.strike=c->sgr.strikethrough, .dim=c->sgr.dim, .blink=c->sgr.blink};
|
||||
return ans;
|
||||
}
|
||||
|
||||
@@ -188,6 +189,7 @@ static inline void
|
||||
attrs_to_cursor(const CellAttrs attrs, Cursor *c) {
|
||||
c->sgr.decoration = attrs.decoration; c->sgr.bold = attrs.bold; c->sgr.italic = attrs.italic;
|
||||
c->sgr.reverse = attrs.reverse; c->sgr.strikethrough = attrs.strike; c->sgr.dim = attrs.dim;
|
||||
c->sgr.blink = attrs.blink;
|
||||
}
|
||||
|
||||
#define cursor_as_gpu_cell(cursor) {.attrs=cursor_to_attrs(cursor), .fg=(cursor->sgr.fg & COL_MASK), .bg=(cursor->sgr.bg & COL_MASK), .decoration_fg=cursor->sgr.decoration_fg & COL_MASK}
|
||||
|
||||
@@ -10,6 +10,7 @@ from typing import Any, Literal, NamedTuple, Optional
|
||||
from .constants import read_kitty_resource
|
||||
from .fast_data_types import (
|
||||
BGIMAGE_PROGRAM,
|
||||
BLINK,
|
||||
BLIT_PROGRAM,
|
||||
CELL_BG_PROGRAM,
|
||||
CELL_FG_PROGRAM,
|
||||
@@ -172,6 +173,7 @@ class LoadShaderPrograms:
|
||||
REVERSE_SHIFT=REVERSE,
|
||||
STRIKE_SHIFT=STRIKETHROUGH,
|
||||
DIM_SHIFT=DIM,
|
||||
BLINK_SHIFT=BLINK,
|
||||
DECORATION_SHIFT=DECORATION,
|
||||
MARK_SHIFT=MARK,
|
||||
MARK_MASK=MARK_MASK,
|
||||
|
||||
@@ -112,7 +112,6 @@ class TestScreen(BaseTest):
|
||||
ln = s.line(0)
|
||||
self.ae(txt, ln.as_ansi())
|
||||
|
||||
|
||||
def test_rep(self):
|
||||
s = self.create_screen()
|
||||
s.draw('a')
|
||||
@@ -618,11 +617,13 @@ class TestScreen(BaseTest):
|
||||
|
||||
def test_sgr(self):
|
||||
s = self.create_screen()
|
||||
s.select_graphic_rendition(0, 1, 37, 42)
|
||||
s.select_graphic_rendition(0, 1, 5, 37, 42)
|
||||
s.draw('a')
|
||||
c = s.line(0).cursor_from(0)
|
||||
self.assertTrue(c.bold)
|
||||
self.assertTrue(c.blink)
|
||||
self.ae(c.bg, (2 << 8) | 1)
|
||||
self.ae('\x1b[22;1;5;37;42ma', s.line(0).as_ansi())
|
||||
s.cursor_position(2, 1)
|
||||
s.select_graphic_rendition(0, 35)
|
||||
s.draw('b')
|
||||
|
||||
Reference in New Issue
Block a user