Skip to content

Commit

Permalink
Pass the basic colors of the underlying window as an env var when run…
Browse files Browse the repository at this point in the history
…ning a UI kitten

Allows UI kittens to choose colors without needing a roundtrip to query
the terminal for colors
  • Loading branch information
kovidgoyal committed Jan 17, 2025
1 parent 069868f commit 182bd9c
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 16 deletions.
2 changes: 2 additions & 0 deletions kitty/boss.py
Original file line number Diff line number Diff line change
Expand Up @@ -1976,6 +1976,8 @@ def run_kitten_with_metadata(
cmd = [kitten_exe(), kitten]
env['KITTEN_RUNNING_AS_UI'] = '1'
env['KITTY_CONFIG_DIRECTORY'] = config_dir
if w is not None:
env['KITTY_BASIC_COLORS'] = json.dumps(w.screen.color_profile.basic_colors())
else:
cmd = [kitty_exe(), '+runpy', 'from kittens.runner import main; main()']
env['PYTHONWARNINGS'] = 'ignore'
Expand Down
52 changes: 38 additions & 14 deletions kitty/colors.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,32 +305,55 @@ colorprofile_to_color_with_fallback(ColorProfile *self, DynamicColor entry, Dyna
}
static Color* alloc_color(unsigned char r, unsigned char g, unsigned char b, unsigned a);

static PyObject*
as_dict(ColorProfile *self, PyObject *args UNUSED) {
#define as_dict_doc "Return all colors as a dictionary of color_name to integer or None (names are the same as used in kitty.conf)"
RAII_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);
static bool
colortable_colors_into_dict(ColorProfile *self, unsigned start, unsigned limit, PyObject *ans) {
static char buf[32] = {'c', 'o', 'l', 'o', 'r', 0};
for (unsigned i = start; i < limit; i++) {
snprintf(buf + 5, sizeof(buf) - 6, "%u", i);
PyObject *val = PyLong_FromUnsignedLong(self->color_table[i]);
if (!val) { return PyErr_NoMemory(); }
if (!val) return false;
int ret = PyDict_SetItemString(ans, buf, val);
Py_CLEAR(val);
if (ret != 0) { return NULL; }
Py_DECREF(val);
if (ret != 0) return false;
}
return true;
}

static PyObject*
basic_colors(ColorProfile *self, PyObject *args UNUSED) {
#define basic_colors_doc "Return the basic colors as a dictionary of color_name to integer or None (names are the same as used in kitty.conf)"
RAII_PyObject(ans, PyDict_New()); if (ans == NULL) return NULL;
if (!colortable_colors_into_dict(self, 0, 16, ans)) return NULL;

#define D(attr, name) { \
unsigned long c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
PyObject *val = PyLong_FromUnsignedLong(c); if (!val) return NULL; \
int ret = PyDict_SetItemString(ans, #name, val); Py_DECREF(val); \
if (ret != 0) return NULL; \
}

D(default_fg, foreground); D(default_bg, background);
#undef D
return Py_NewRef(ans);
}

static PyObject*
as_dict(ColorProfile *self, PyObject *args UNUSED) {
#define as_dict_doc "Return all colors as a dictionary of color_name to integer or None (names are the same as used in kitty.conf)"
RAII_PyObject(ans, PyDict_New()); if (ans == NULL) return NULL;
if (!colortable_colors_into_dict(self, 0, arraysz(self->color_table), ans)) return NULL;
#define D(attr, name) { \
if (self->overridden.attr.type != COLOR_NOT_SET) { \
int ret; PyObject *val; \
if (self->overridden.attr.type == COLOR_IS_SPECIAL) { \
val = Py_None; Py_INCREF(val); \
val = Py_NewRef(Py_None); \
} else { \
color_type c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
unsigned long c = colorprofile_to_color(self, self->overridden.attr, self->configured.attr).rgb; \
val = PyLong_FromUnsignedLong(c); \
} \
if (!val) { return NULL; } \
ret = PyDict_SetItemString(ans, #name, val); \
Py_CLEAR(val); \
Py_DECREF(val); \
if (ret != 0) { return NULL; } \
}}
D(default_fg, foreground); D(default_bg, background);
Expand Down Expand Up @@ -597,6 +620,7 @@ set_transparent_background_color(ColorProfile *self, PyObject *const *args, Py_s
static PyMethodDef cp_methods[] = {
METHOD(reset_color_table, METH_NOARGS)
METHOD(as_dict, METH_NOARGS)
METHOD(basic_colors, METH_NOARGS)
METHOD(color_table_address, METH_NOARGS)
METHOD(as_color, METH_O)
METHOD(reset_color, METH_O)
Expand Down
4 changes: 2 additions & 2 deletions kitty/fast_data_types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,8 @@ class ColorProfile:

def __init__(self, opts: Optional[Options] = None): ...

def as_dict(self) -> Dict[str, int | None | tuple[tuple[Color, float], ...]]:
pass
def as_dict(self) -> Dict[str, int | None | tuple[tuple[Color, float], ...]]: ...
def basic_colors(self) -> Dict[str, int | None | tuple[tuple[Color, float], ...]]: ...

def as_color(self, val: int) -> Optional[Color]:
pass
Expand Down

0 comments on commit 182bd9c

Please sign in to comment.