From 3031d41e72d50d92aa6a1bbc18a8f61ddcb78df3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 24 Nov 2016 15:28:52 +0530 Subject: [PATCH] Start work on supporting changing of entries in the color table --- kitty/boss.py | 3 ++ kitty/colors.c | 73 +++++++-------------------------------- kitty/config.py | 20 ++--------- kitty/data-types.h | 5 +-- kitty/parser.c | 9 +++-- kitty/screen.c | 19 +++++++--- kitty/terminfo.py | 6 ++-- kitty_tests/datatypes.py | 4 +-- kitty_tests/parser.py | 12 +++---- terminfo/kitty.terminfo | 1 + terminfo/x/xterm-kitty | Bin 1641 -> 1735 bytes 11 files changed, 53 insertions(+), 99 deletions(-) diff --git a/kitty/boss.py b/kitty/boss.py index b304d6df6..9d97ef875 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -274,6 +274,9 @@ class Boss(Thread): code += 1 self.queue_action(self.apply_change_colors) + def set_color_table_color(self, code, value): + print(11111111, code, value) + def apply_change_colors(self): self.char_grid.change_colors(self.pending_color_changes) self.pending_color_changes = {} diff --git a/kitty/colors.c b/kitty/colors.c index 0b209e3b1..71214c3b3 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -57,7 +57,8 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) { self = (ColorProfile *)type->tp_alloc(type, 0); if (self != NULL) { if (FG_BG_256[255] == 0) create_256_color_table(); - memcpy(self->color_table_256, FG_BG_256, sizeof(FG_BG_256)); + memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256)); + memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256)); } return (PyObject*) self; } @@ -72,78 +73,32 @@ static PyObject* update_ansi_color_table(ColorProfile *self, PyObject *val) { #define update_ansi_color_table_doc "Update the 16 basic colors" index_type i; - PyObject *t; if (!PyList_Check(val)) { PyErr_SetString(PyExc_TypeError, "color table must be a list"); return NULL; } - -#define TO_COLOR \ - t = PyList_GET_ITEM(val, i); \ - self->ansi_color_table[i] = PyLong_AsUnsignedLong(t); - - for(i = 30; i < 38; i++) { - TO_COLOR; - } - i = 39; TO_COLOR; - for(i = 90; i < 98; i++) { - TO_COLOR; - } - i = 99; TO_COLOR; - for(i = 40; i < 48; i++) { - TO_COLOR; - } - i = 49; TO_COLOR; - for(i = 100; i < 108; i++) { - TO_COLOR; + if (PyList_GET_SIZE(val) != 16) { PyErr_SetString(PyExc_TypeError, "color table must have 16 items"); return NULL; } + for (i = 0; i < 16; i++) { + self->color_table[i] = PyLong_AsUnsignedLong(PyList_GET_ITEM(val, i)); + self->orig_color_table[i] = self->color_table[i]; } Py_RETURN_NONE; } -static PyObject* -ansi_color(ColorProfile *self, PyObject *val) { -#define ansi_color_doc "Return the color at the specified index" - if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; } - unsigned long idx = PyLong_AsUnsignedLong(val); - if (idx >= sizeof(self->ansi_color_table) / sizeof(self->ansi_color_table[0])) { - PyErr_SetString(PyExc_IndexError, "Out of bounds"); return NULL; - } - return PyLong_FromUnsignedLong(self->ansi_color_table[idx]); -} - -static PyObject* -color_256(ColorProfile *self, PyObject *val) { -#define color_256_doc "Return the color at the specified 256-color index" - if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; } - unsigned long idx = PyLong_AsUnsignedLong(val); - if (idx >= 256) { - PyErr_SetString(PyExc_IndexError, "Out of bounds"); return NULL; - } - return PyLong_FromUnsignedLong(self->color_table_256[idx]); -} - static PyObject* as_color(ColorProfile *self, PyObject *val) { #define as_color_doc "Convert the specified terminal color into an (r, g, b) tuple based on the current profile values" if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "val must be an int"); return NULL; } unsigned long entry = PyLong_AsUnsignedLong(val); unsigned int t = entry & 0xFF; - uint8_t r, g, b; + uint8_t r; uint32_t col = 0; PyObject *ans = NULL; switch(t) { case 1: r = (entry >> 8) & 0xff; - col = self->ansi_color_table[r]; + col = self->color_table[r]; break; case 2: - r = (entry >> 8) & 0xff; - col = self->color_table_256[r]; - break; - case 3: - r = (entry >> 8) & 0xff; - g = (entry >> 16) & 0xff; - b = (entry >> 24) & 0xff; - ans = Py_BuildValue("BBB", r, g, b); - break; + col = entry >> 8; default: ans = Py_None; Py_INCREF(Py_None); } @@ -151,16 +106,14 @@ as_color(ColorProfile *self, PyObject *val) { return ans; } -uint32_t to_color(ColorProfile *self, uint32_t entry, uint32_t defval) { +uint32_t +to_color(ColorProfile *self, uint32_t entry, uint32_t defval) { unsigned int t = entry & 0xFF, r; switch(t) { case 1: r = (entry >> 8) & 0xff; - return self->ansi_color_table[r]; + return self->color_table[r]; case 2: - r = (entry >> 8) & 0xff; - return self->color_table_256[r]; - case 3: return entry >> 8; default: return defval; @@ -172,8 +125,6 @@ uint32_t to_color(ColorProfile *self, uint32_t entry, uint32_t defval) { static PyMethodDef methods[] = { METHOD(update_ansi_color_table, METH_O) - METHOD(ansi_color, METH_O) - METHOD(color_256, METH_O) METHOD(as_color, METH_O) {NULL} /* Sentinel */ }; diff --git a/kitty/config.py b/kitty/config.py index 12531eb0e..995eeebfc 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -5,7 +5,6 @@ import re import sys from collections import namedtuple -from itertools import repeat import glfw_constants as glfw @@ -215,7 +214,7 @@ type_map = { 'repaint_delay': int, } -for name in 'foreground foreground_bold background cursor'.split(): +for name in 'foreground background cursor'.split(): type_map[name] = lambda x: to_color(x, validate=True) for i in range(16): type_map['color%d' % i] = lambda x: to_color(x, validate=True) @@ -271,9 +270,6 @@ foreground #dddddd # The background color background #000000 -# The high intensity foreground color -foreground_bold #ffffff - # The cursor color cursor #ffffff @@ -385,16 +381,4 @@ def build_ansi_color_table(opts: Options=defaults): def col(i): return as_int(getattr(opts, 'color{}'.format(i))) - ans = list(repeat(0, 120)) - fg = {30 + i: col(i) for i in range(8)} - fg[39] = as_int(opts.foreground) - fg.update({90 + i: col(i + 8) for i in range(8)}) - fg[99] = as_int(opts.foreground_bold) - bg = {40 + i: col(i) for i in range(8)} - bg[49] = as_int(opts.background) - bg.update({100 + i: col(i + 8) for i in range(8)}) - for k, val in fg.items(): - ans[k] = val - for k, val in bg.items(): - ans[k] = val - return ans + return list(map(col, range(16))) diff --git a/kitty/data-types.h b/kitty/data-types.h index 0cc18b456..126f56e8c 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -179,8 +179,8 @@ PyTypeObject Cursor_Type; typedef struct { PyObject_HEAD - uint32_t color_table_256[256]; - uint32_t ansi_color_table[120]; + uint32_t color_table[256]; + uint32_t orig_color_table[256]; } ColorProfile; PyTypeObject ColorProfile_Type; @@ -364,6 +364,7 @@ void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom); void set_title(Screen *self, PyObject*); void set_icon(Screen *self, PyObject*); void set_dynamic_color(Screen *self, unsigned int code, PyObject*); +void set_color_table_color(Screen *self, unsigned int code, PyObject*); void screen_request_capabilities(Screen *, PyObject *); void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary); void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count); diff --git a/kitty/parser.c b/kitty/parser.c index 369d22353..7e73e5c04 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -198,6 +198,7 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal static inline void dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { #define DISPATCH_OSC(name) REPORT_OSC(name, string); name(screen, string); +#define SET_COLOR(name) REPORT_OSC(name, string); name(screen, code, string); const unsigned int limit = screen->parser_buf_pos; unsigned int code=0, i; for (i = 0; i < MIN(limit, 5); i++) { @@ -220,12 +221,15 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { case 2: DISPATCH_OSC(set_title); break; + case 4: + case 104: + SET_COLOR(set_color_table_color); + break; case 10: case 11: case 110: case 111: - REPORT_OSC(set_dynamic_color, string); - set_dynamic_color(screen, code, string); + SET_COLOR(set_dynamic_color); break; default: REPORT_ERROR("Unknown OSC code: %u", code); @@ -234,6 +238,7 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { Py_CLEAR(string); } #undef DISPATCH_OSC +#undef SET_COLOR } // }}} diff --git a/kitty/screen.c b/kitty/screen.c index 33a524220..2478050ec 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -199,14 +199,14 @@ void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int c switch(attr) { \ case 5: \ if (i < count) \ - self->cursor->which = (params[i++] & 0xFF) << 8 | 2; \ + self->cursor->which = (params[i++] & 0xFF) << 8 | 1; \ break; \ case 2: \ if (i < count - 2) { \ r = params[i++] & 0xFF; \ g = params[i++] & 0xFF; \ b = params[i++] & 0xFF; \ - self->cursor->which = r << 24 | g << 16 | b << 8 | 3; \ + self->cursor->which = r << 24 | g << 16 | b << 8 | 2; \ }\ break; \ } \ @@ -243,14 +243,18 @@ void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int c self->cursor->strikethrough = false; break; START_ALLOW_CASE_RANGE case 30 ... 37: + self->cursor->fg = ((attr - 30) << 8) | 1; break; case 39: - case 90 ... 97: - self->cursor->fg = (attr << 8) | 1; break; + self->cursor->fg = 0; break; case 40 ... 47: + self->cursor->bg = ((attr - 40) << 8) | 1; break; case 49: + self->cursor->bg = 0; break; + case 90 ... 97: + self->cursor->fg = ((attr - 90 + 8) << 8) | 1; break; case 100 ... 107: + self->cursor->bg = ((attr - 100 + 8) << 8) | 1; break; END_ALLOW_CASE_RANGE - self->cursor->bg = (attr << 8) | 1; break; case 38: SET_COLOR(fg); case 48: @@ -810,6 +814,11 @@ void set_dynamic_color(Screen *self, unsigned int code, PyObject *color) { if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } } +void set_color_table_color(Screen *self, unsigned int code, PyObject *color) { + PyObject_CallMethod(self->callbacks, "set_color_table_color", "IO", code, color); + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } +} + void screen_request_capabilities(Screen *self, PyObject *q) { PyObject_CallMethod(self->callbacks, "request_capabilities", "O", q); if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } diff --git a/kitty/terminfo.py b/kitty/terminfo.py index ca286530c..5589e0e79 100644 --- a/kitty/terminfo.py +++ b/kitty/terminfo.py @@ -130,8 +130,8 @@ string_capabilities = { 'ind': r'^J', 'indn': r'\E[%p1%dS', # initialize color (set dynamic colors) - # 'initc': r'\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\', - # Set all color pairs to original values + 'initc': r'\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\', + # Set all colors to original values 'oc': r'\E]104\007', # turn on blank mode (characters invisible) # 'invis': r'\E[8m', @@ -278,7 +278,7 @@ termcap_aliases.update({ 'al': 'il1', 'sf': 'ind', 'SF': 'indn', - # 'Ic': 'initc', + 'Ic': 'initc', 'oc': 'oc', # 'mk': 'invis', 'kb': 'kbs', diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 2102a59c0..7c853402f 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -273,8 +273,8 @@ class TestDataTypes(BaseTest): c.update_ansi_color_table(build_ansi_color_table()) for i in range(8): col = getattr(defaults, 'color{}'.format(i)) - self.assertEqual(c.ansi_color(30 + i), col[0] << 16 | col[1] << 8 | col[2]) - self.ae(c.color_256(255), 0xeeeeee) + self.assertEqual(c.as_color(i << 8 | 1), (col[0], col[1], col[2])) + self.ae(c.as_color(255 << 8 | 1), (0xee, 0xee, 0xee)) def test_sprite_map(self): s = SpriteMap(10, 2) diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index d2ba640ec..183dcf73f 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -123,14 +123,14 @@ class TestParser(BaseTest): for attr in 'bold italic reverse strikethrough'.split(): self.assertTrue(getattr(s.cursor, attr)) self.ae(s.cursor.decoration, 1) - self.ae(s.cursor.fg, 34 << 8 | 1) - self.ae(s.cursor.bg, 44 << 8 | 1) + self.ae(s.cursor.fg, 4 << 8 | 1) + self.ae(s.cursor.bg, 4 << 8 | 1) pb('\033[38;5;1;48;5;7m', ('select_graphic_rendition', 6)) - self.ae(s.cursor.fg, 1 << 8 | 2) - self.ae(s.cursor.bg, 7 << 8 | 2) + self.ae(s.cursor.fg, 1 << 8 | 1) + self.ae(s.cursor.bg, 7 << 8 | 1) pb('\033[38;2;1;2;3;48;2;7;8;9m', ('select_graphic_rendition', 10)) - self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 3) - self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 3) + self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 2) + self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 2) c = Callbacks() s.callbacks = c pb('\033[5n', ('report_device_status', 5, 0)) diff --git a/terminfo/kitty.terminfo b/terminfo/kitty.terminfo index 2fb03b744..3752d874e 100644 --- a/terminfo/kitty.terminfo +++ b/terminfo/kitty.terminfo @@ -50,6 +50,7 @@ xterm-kitty|KovIdTTY, il1=\E[L, ind=^J, indn=\E[%p1%dS, + initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, kEND=\E[1;2F, kHOM=\E[1;2H, kLFT=\E[1;2D, diff --git a/terminfo/x/xterm-kitty b/terminfo/x/xterm-kitty index 88bffb44f48132dde860ce3ef886741e40fd7051..8dcc29d13e987b4648e3dc004c61474ee073d325 100644 GIT binary patch delta 168 zcmaFKbDWo3icyq7hJl|UlX2!o?&VC3YbS4H5*OoU{*M6!m?sM|Iq`@=rKFf6nK$b( zuVaddHL+GLFjP&kE=o_bQY|o2tu`_>tyR@htu{0;FsN14S2fZziqKarFvclkf?Y;B JX7Vl8egNqdI}88- delta 73 zcmX@k`;v!Sicyq7hJl|UlhJx3_j0Dmf{YSkYnlFIfK5OtCMTX9P^mpkznM1cF|T8q IY{k|K0KCN{wEzGB