From f820f72768eb587005ed3f108de4c61caf56623b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 18 Jun 2018 10:02:05 +0530 Subject: [PATCH] Add a kitty @ get-colors command --- kitty/cmds.py | 33 +++++++++++++++++++++++++++++++++ kitty/colors.c | 32 ++++++++++++++++++++++++++++++++ kitty/utils.py | 11 +++++++++++ kitty/window.py | 4 ++++ 4 files changed, 80 insertions(+) diff --git a/kitty/cmds.py b/kitty/cmds.py index 68a20d02a..abee06ecd 100644 --- a/kitty/cmds.py +++ b/kitty/cmds.py @@ -10,6 +10,7 @@ from .cli import parse_args from .config import parse_config, parse_send_text_bytes from .constants import appname from .tabs import SpecialWindow +from .utils import natsort_ints class MatchError(ValueError): @@ -607,6 +608,38 @@ def set_colors(boss, window, payload): # }}} +# get_colors {{{ +@cmd( + 'Get terminal colors', + 'Get the terminal colors for the specified window (defaults to active window). Colors will be output to stdout in the same syntax as used for kitty.conf', + options_spec='''\ +--configured -c +type=bool-set +Instead of outputting the colors for the specified window, output the currently +configured colors. + +''' + '\n\n' + MATCH_WINDOW_OPTION +) +def cmd_get_colors(global_opts, opts, args): + return {'configured': opts.configured, 'match': opts.match} + + +def get_colors(boss, window, payload): + from .rgb import Color, color_as_sharp, color_from_int + ans = {k: getattr(boss.opts, k) for k in boss.opts if isinstance(getattr(boss.opts, k), Color)} + if not payload['configured']: + windows = (window or boss.active_window,) + if payload['match']: + windows = tuple(boss.match_windows(payload['match'])) + if not windows: + raise MatchError(payload['match']) + ans.update({k: color_from_int(v) for k, v in windows[0].current_colors.items()}) + all_keys = natsort_ints(ans) + maxlen = max(map(len, all_keys)) + return '\n'.join(('{:%ds} {}' % maxlen).format(key, color_as_sharp(ans[key])) for key in all_keys) +# }}} + + # set_background_opacity {{{ @cmd( 'Set the background_opacity', diff --git a/kitty/colors.c b/kitty/colors.c index 96514455d..175d7200f 100644 --- a/kitty/colors.c +++ b/kitty/colors.c @@ -150,6 +150,37 @@ colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) { } +static PyObject* +as_dict(ColorProfile *self, PyObject *args UNUSED) { +#define as_dict_doc "Return all colors as a dictionary of color_name to integer (names are the same as used in kitty.conf)" + PyObject *ans = PyDict_New(); + if (ans == NULL) return PyErr_NoMemory(); + for (unsigned i = 0; i < arraysz(self->color_table); i++) { + static char buf[32] = {0}; + snprintf(buf, sizeof(buf) - 1, "color%u", i); + PyObject *val = PyLong_FromUnsignedLong(self->color_table[i]); + if (!val) { Py_CLEAR(ans); return PyErr_NoMemory(); } + int ret = PyDict_SetItemString(ans, buf, val); + Py_CLEAR(val); + if (ret != 0) { Py_CLEAR(ans); return NULL; } + } +#define D(attr, name) { \ + color_type c = colorprofile_to_color(self, self->overridden.attr, 0xffffffff); \ + if (c != 0xffffffff) { \ + PyObject *val = PyLong_FromUnsignedLong(c); \ + if (!val) { Py_CLEAR(ans); return PyErr_NoMemory(); } \ + int ret = PyDict_SetItemString(ans, #name, val); \ + Py_CLEAR(val); \ + if (ret != 0) { Py_CLEAR(ans); return NULL; } \ + }} + D(default_fg, foreground); D(default_bg, background); + D(cursor_color, cursor); D(highlight_fg, selection_foreground); + D(highlight_bg, selection_background); + +#undef D + return ans; +} + 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" @@ -275,6 +306,7 @@ static PyMemberDef members[] = { static PyMethodDef methods[] = { METHOD(update_ansi_color_table, METH_O) METHOD(reset_color_table, METH_NOARGS) + METHOD(as_dict, METH_NOARGS) METHOD(color_table_address, METH_NOARGS) METHOD(as_color, METH_O) METHOD(reset_color, METH_O) diff --git a/kitty/utils.py b/kitty/utils.py index b35e69c97..1edbd69ba 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -397,6 +397,17 @@ class TTYIO: break +def natsort_ints(iterable): + + def convert(text): + return int(text) if text.isdigit() else text + + def alphanum_key(key): + return tuple(map(convert, re.split(r'(\d+)', key))) + + return sorted(iterable, key=alphanum_key) + + def get_editor(): import shlex return shlex.split(os.environ.get('EDITOR', 'vim')) diff --git a/kitty/window.py b/kitty/window.py index 0101508d1..35ddd4a1c 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -133,6 +133,10 @@ class Window: cwd=self.child.current_cwd or self.child.cwd, cmdline=self.child.cmdline ) + @property + def current_colors(self): + return self.screen.color_profile.as_dict() + def matches(self, field, pat): if field == 'id': return pat.pattern == str(self.id)