mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-04 14:46:03 +00:00
A new option second_transparent_bg
Makes a second background color semi-transparent via background_opacity. Useful for things like cursor line highlight in editors. Fixes #7646
This commit is contained in:
parent
573058d861
commit
0cf9a79760
25 changed files with 293 additions and 314 deletions
|
|
@ -78,6 +78,8 @@ Detailed list of changes
|
|||
|
||||
- launch command: A new :option:`launch --bias` option to adjust the size of newly created windows declaratively (:iss:`7634`)
|
||||
|
||||
- A new option :opt:`second_transparent_bg` to make a second background color semi-transparent via :opt:`background_opacity`. Useful for things like cursor line highlight in editors (:iss:`7646`)
|
||||
|
||||
- Sessions: A new command ``focus_matching_window`` to shift focus to a specific window, useful when creating complex layouts with splits (:disc:`7635`)
|
||||
|
||||
- Wayland: Allow fractional scales less than one (:pull:`7549`)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ def patch_color_list(path: str, colors: List[str], name: str, spc: str = ' ')
|
|||
|
||||
def main(args: List[str]=sys.argv) -> None:
|
||||
from kitty.options.definition import definition
|
||||
write_output('kitty', definition)
|
||||
nullable_colors = []
|
||||
all_colors = []
|
||||
for opt in definition.iter_all_options():
|
||||
|
|
@ -52,9 +51,10 @@ def main(args: List[str]=sys.argv) -> None:
|
|||
all_colors.append(opt.name)
|
||||
elif opt.parser_func.__name__ in ('to_color', 'titlebar_color', 'macos_titlebar_color'):
|
||||
all_colors.append(opt.name)
|
||||
patch_color_list('kitty/rc/set_colors.py', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('tools/cmd/at/set_colors.go', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('tools/themes/collection.go', all_colors, 'ALL')
|
||||
nc = '\n '.join(f'{x!r}' for x in nullable_colors)
|
||||
write_output('kitty', definition, f'\nnullable_colors = frozenset({{\n {nc}\n}})')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -179,14 +179,12 @@ class Foreground(Query):
|
|||
|
||||
@staticmethod
|
||||
def get_result(opts: Options, window_id: int, os_window_id: int) -> str:
|
||||
from kitty.fast_data_types import Color, get_boss
|
||||
from kitty.fast_data_types import get_boss, get_options
|
||||
boss = get_boss()
|
||||
w = boss.window_id_map.get(window_id)
|
||||
if w is None:
|
||||
return opts.foreground.as_sharp
|
||||
col = w.screen.color_profile.default_fg
|
||||
r, g, b = col >> 16, (col >> 8) & 0xff, col & 0xff
|
||||
return Color(r, g, b).as_sharp
|
||||
return (w.screen.color_profile.default_fg or get_options().foreground).as_sharp
|
||||
|
||||
|
||||
@query
|
||||
|
|
@ -196,15 +194,12 @@ class Background(Query):
|
|||
|
||||
@staticmethod
|
||||
def get_result(opts: Options, window_id: int, os_window_id: int) -> str:
|
||||
from kitty.fast_data_types import Color, get_boss
|
||||
from kitty.fast_data_types import get_boss, get_options
|
||||
boss = get_boss()
|
||||
w = boss.window_id_map.get(window_id)
|
||||
if w is None:
|
||||
return opts.background.as_sharp
|
||||
col = w.screen.color_profile.default_bg
|
||||
r, g, b = col >> 16, (col >> 8) & 0xff, col & 0xff
|
||||
return Color(r, g, b).as_sharp
|
||||
|
||||
return (w.screen.color_profile.default_bg or get_options().background).as_sharp
|
||||
|
||||
|
||||
@query
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from typing import Iterable, NamedTuple, Sequence
|
|||
from .fast_data_types import BORDERS_PROGRAM, add_borders_rect, get_options, init_borders_program, os_window_has_background_image
|
||||
from .shaders import program_for
|
||||
from .typing import LayoutType
|
||||
from .utils import color_as_int
|
||||
from .window_list import WindowGroup, WindowList
|
||||
|
||||
|
||||
|
|
@ -96,7 +97,7 @@ class Borders:
|
|||
active_group = all_windows.active_group
|
||||
|
||||
for i, wg in enumerate(groups):
|
||||
window_bg = wg.default_bg
|
||||
window_bg = color_as_int(wg.default_bg)
|
||||
window_bg = (window_bg << 8) | BorderColor.window_bg
|
||||
if draw_borders and not draw_minimal_borders:
|
||||
# Draw the border rectangles
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ from .key_encoding import get_name_to_functional_number_map
|
|||
from .keys import Mappings
|
||||
from .layout.base import set_layout_options
|
||||
from .notify import notification_activated
|
||||
from .options.types import Options
|
||||
from .options.types import Options, nullable_colors
|
||||
from .options.utils import MINIMUM_FONT_SIZE, KeyboardMode, KeyDefinition
|
||||
from .os_window_size import initial_window_size_func
|
||||
from .rgb import color_from_int
|
||||
|
|
@ -342,9 +342,9 @@ class Boss:
|
|||
self.clipboard_buffers: Dict[str, str] = {}
|
||||
self.update_check_process: Optional['PopenType[bytes]'] = None
|
||||
self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary()
|
||||
self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)}
|
||||
self.color_settings_at_startup: Dict[str, Optional[Color]] = {
|
||||
k: opts[k] for k in opts if isinstance(opts[k], Color) or k in nullable_colors}
|
||||
self.current_visual_select: Optional[VisualSelect] = None
|
||||
self.startup_cursor_text_color = opts.cursor_text_color
|
||||
# A list of events received so far that are potentially part of a sequence keybinding.
|
||||
self.cached_values = cached_values
|
||||
self.os_window_map: Dict[int, TabManager] = {}
|
||||
|
|
@ -2627,7 +2627,6 @@ class Boss:
|
|||
window.refresh()
|
||||
|
||||
def patch_colors(self, spec: Dict[str, Optional[int]], configured: bool = False) -> None:
|
||||
from kitty.rc.set_colors import nullable_colors
|
||||
opts = get_options()
|
||||
if configured:
|
||||
for k, v in spec.items():
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
layout(std140) uniform CellRenderData {
|
||||
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_fg, use_cell_for_selection_bg;
|
||||
|
||||
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
|
||||
|
||||
uint xnum, ynum, cursor_fg_sprite_idx;
|
||||
float cursor_x, cursor_y, cursor_w, cursor_opacity;
|
||||
|
|
@ -194,7 +194,9 @@ void main() {
|
|||
// }}}
|
||||
|
||||
// Background {{{
|
||||
float cell_has_non_default_bg = step(1, float(abs(bg_as_uint - default_colors[1])));
|
||||
float cell_has_non_default_bg = step(1, float(abs(
|
||||
(bg_as_uint - default_colors[1]) * (bg_as_uint - second_transparent_bg)
|
||||
)));
|
||||
draw_bg = 1;
|
||||
|
||||
#if (PHASE == PHASE_BACKGROUND)
|
||||
|
|
|
|||
199
kitty/colors.c
199
kitty/colors.c
|
|
@ -47,7 +47,8 @@ init_FG_BG_table(void) {
|
|||
}
|
||||
}
|
||||
|
||||
PyObject* create_256_color_table(void) {
|
||||
static PyObject*
|
||||
create_256_color_table(void) {
|
||||
init_FG_BG_table();
|
||||
PyObject *ans = PyTuple_New(arraysz(FG_BG_256));
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
|
|
@ -59,21 +60,88 @@ PyObject* create_256_color_table(void) {
|
|||
return ans;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
new_cp(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
ColorProfile *self;
|
||||
static bool
|
||||
set_configured_colors(ColorProfile *self, PyObject *opts) {
|
||||
#define n(which, attr) { \
|
||||
RAII_PyObject(t, PyObject_GetAttrString(opts, #attr)); \
|
||||
if (t == NULL) return false; \
|
||||
if (t == Py_None) { self->configured.which.rgb = 0; self->configured.which.type = COLOR_IS_SPECIAL; } \
|
||||
else if (PyLong_Check(t)) { \
|
||||
unsigned int x = PyLong_AsUnsignedLong(t); \
|
||||
self->configured.which.rgb = x & 0xffffff; \
|
||||
self->configured.which.type = COLOR_IS_RGB; \
|
||||
} else if (PyObject_TypeCheck(t, &Color_Type)) { \
|
||||
Color *c = (Color*)t; \
|
||||
self->configured.which.rgb = c->color.rgb; \
|
||||
self->configured.which.type = COLOR_IS_RGB; \
|
||||
} else { PyErr_SetString(PyExc_TypeError, "colors must be integers or Color objects"); return false; } \
|
||||
}
|
||||
|
||||
n(default_fg, foreground); n(default_bg, background);
|
||||
n(cursor_color, cursor); n(cursor_text_color, cursor_text_color);
|
||||
n(highlight_fg, selection_foreground); n(highlight_bg, selection_background);
|
||||
n(visual_bell_color, visual_bell_color); n(second_transparent_bg, second_transparent_bg);
|
||||
#undef n
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_mark_colors(ColorProfile *self, PyObject *opts) {
|
||||
char fgattr[] = "mark?_foreground", bgattr[] = "mark?_background";
|
||||
#define n(i, attr, which) { \
|
||||
attr[4] = '1' + i; \
|
||||
RAII_PyObject(t, PyObject_GetAttrString(opts, attr)); \
|
||||
if (t == NULL) return false; \
|
||||
if (!PyObject_TypeCheck(t, &Color_Type)) { PyErr_SetString(PyExc_TypeError, "mark color is not Color object"); return false; } \
|
||||
Color *c = (Color*)t; self->which[i] = c->color.rgb; \
|
||||
}
|
||||
#define m(i) n(i, fgattr, mark_foregrounds); n(i, bgattr, mark_backgrounds);
|
||||
m(0); m(1); m(2);
|
||||
#undef m
|
||||
#undef n
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_colortable(ColorProfile *self, PyObject *opts) {
|
||||
RAII_PyObject(ct, PyObject_GetAttrString(opts, "color_table"));
|
||||
if (!ct) return false;
|
||||
RAII_PyObject(ret, PyObject_CallMethod(ct, "buffer_info", NULL));
|
||||
if (!ret) return false;
|
||||
unsigned long *color_table = PyLong_AsVoidPtr(PyTuple_GET_ITEM(ret, 0));
|
||||
size_t count = PyLong_AsSize_t(PyTuple_GET_ITEM(ret, 1));
|
||||
if (!color_table || count != arraysz(FG_BG_256)) { PyErr_SetString(PyExc_TypeError, "color_table has incorrect length"); return false; }
|
||||
RAII_PyObject(r2, PyObject_GetAttrString(ct, "itemsize")); if (!r2) return false;
|
||||
size_t itemsize = PyLong_AsSize_t(r2);
|
||||
if (itemsize != sizeof(unsigned long)) { PyErr_Format(PyExc_TypeError, "color_table has incorrect itemsize: %zu", itemsize); return false; }
|
||||
for (size_t i = 0; i < arraysz(FG_BG_256); i++) self->color_table[i] = color_table[i];
|
||||
memcpy(self->orig_color_table, self->color_table, arraysz(self->color_table) * sizeof(self->color_table[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
new_cp(PyTypeObject *type, PyObject *args, PyObject *kwds) {
|
||||
PyObject *opts = global_state.options_object;
|
||||
ColorProfile *self;
|
||||
static const char* kw[] = {"opts", NULL};
|
||||
if (args && !PyArg_ParseTupleAndKeywords(args, kwds, "|O", (char**)kw, &opts)) return NULL;
|
||||
self = (ColorProfile *)type->tp_alloc(type, 0);
|
||||
RAII_PyObject(ans, (PyObject*)self);
|
||||
if (self != NULL) {
|
||||
init_FG_BG_table();
|
||||
memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
#define S(which) self->mark_foregrounds[which] = OPT(mark##which##_foreground); self->mark_backgrounds[which] = OPT(mark##which##_background)
|
||||
S(1); S(2); S(3);
|
||||
#undef S
|
||||
if (opts) {
|
||||
if (!set_configured_colors(self, opts)) return NULL;
|
||||
if (!set_mark_colors(self, opts)) return NULL;
|
||||
if (!set_colortable(self, opts)) return NULL;
|
||||
} else {
|
||||
memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
}
|
||||
self->dirty = true;
|
||||
Py_INCREF(ans);
|
||||
}
|
||||
return (PyObject*) self;
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -88,19 +156,6 @@ alloc_color_profile(void) {
|
|||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
update_ansi_color_table(ColorProfile *self, PyObject *val) {
|
||||
#define update_ansi_color_table_doc "Update the 256 basic colors"
|
||||
if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "color table must be a long"); return NULL; }
|
||||
unsigned long *color_table = PyLong_AsVoidPtr(val);
|
||||
for (size_t i = 0; i < arraysz(FG_BG_256); i++) {
|
||||
self->color_table[i] = color_table[i];
|
||||
self->orig_color_table[i] = color_table[i];
|
||||
}
|
||||
self->dirty = true;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
copy_color_profile(ColorProfile *dest, ColorProfile *src) {
|
||||
memcpy(dest->color_table, src->color_table, sizeof(dest->color_table));
|
||||
|
|
@ -171,6 +226,7 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
|
|||
S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color);
|
||||
S(selection_foreground, highlight_fg); S(selection_background, highlight_bg);
|
||||
S(cursor_text_color, cursor_text_color); S(visual_bell_color, visual_bell_color);
|
||||
S(second_transparent_bg, second_transparent_bg);
|
||||
#undef SI
|
||||
#undef S
|
||||
Py_RETURN_NONE;
|
||||
|
|
@ -239,7 +295,7 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
|
|||
}}
|
||||
D(default_fg, foreground); D(default_bg, background);
|
||||
D(cursor_color, cursor); D(cursor_text_color, cursor_text); D(highlight_fg, selection_foreground);
|
||||
D(highlight_bg, selection_background); D(visual_bell_color, visual_bell_color);
|
||||
D(highlight_bg, selection_background); D(visual_bell_color, visual_bell_color); D(second_transparent_bg, second_transparent_bg);
|
||||
|
||||
#undef D
|
||||
return ans;
|
||||
|
|
@ -300,21 +356,6 @@ set_color(ColorProfile *self, PyObject *args) {
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_configured_colors(ColorProfile *self, PyObject *args) {
|
||||
#define set_configured_colors_doc "Set the configured colors"
|
||||
unsigned int default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg, visual_bell_color;
|
||||
if (!PyArg_ParseTuple(args, "II|IIIII", &default_fg, &default_bg,
|
||||
&cursor_color, &cursor_text_color, &highlight_fg, &highlight_bg, &visual_bell_color)) return NULL;
|
||||
#define S(which) \
|
||||
self->configured.which.rgb = which & 0xffffff; \
|
||||
self->configured.which.type = (which & 0xff000000) ? COLOR_IS_RGB : COLOR_IS_SPECIAL;
|
||||
S(default_fg); S(default_bg); S(cursor_color); S(cursor_text_color); S(highlight_fg); S(highlight_bg); S(visual_bell_color);
|
||||
#undef S
|
||||
self->dirty = true;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size_t stride) {
|
||||
size_t i;
|
||||
|
|
@ -404,23 +445,39 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) {
|
|||
|
||||
// Boilerplate {{{
|
||||
|
||||
#define CGETSET(name) \
|
||||
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { return PyLong_FromUnsignedLong(colorprofile_to_color(self, self->overridden.name, self->configured.name).rgb); } \
|
||||
static Color* alloc_color(unsigned char r, unsigned char g, unsigned char b, unsigned a);
|
||||
#define CGETSET(name, nullable) \
|
||||
static PyObject* name##_get(ColorProfile *self, void UNUSED *closure) { \
|
||||
DynamicColor ans = colorprofile_to_color(self, self->overridden.name, self->configured.name); \
|
||||
if (ans.type == COLOR_IS_SPECIAL) { \
|
||||
if (nullable) Py_RETURN_NONE; \
|
||||
return (PyObject*)alloc_color(0, 0, 0, 0); \
|
||||
} \
|
||||
return (PyObject*)alloc_color((ans.rgb >> 16) & 0xff, (ans.rgb >> 8) & 0xff, ans.rgb & 0xff, 0); \
|
||||
} \
|
||||
static int name##_set(ColorProfile *self, PyObject *v, void UNUSED *closure) { \
|
||||
if (v == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute: " #name); return -1; } \
|
||||
unsigned long val = PyLong_AsUnsignedLong(v); \
|
||||
self->overridden.name.rgb = val & 0xffffff; \
|
||||
self->overridden.name.type = (val & 0xff000000) ? COLOR_IS_RGB : COLOR_NOT_SET; \
|
||||
if (v == NULL) { self->overridden.name.val = 0; return 0; } \
|
||||
if (PyLong_Check(v)) { \
|
||||
unsigned long val = PyLong_AsUnsignedLong(v); \
|
||||
self->overridden.name.rgb = val & 0xffffff; \
|
||||
self->overridden.name.type = COLOR_IS_RGB; \
|
||||
} else if (PyObject_TypeCheck(v, &Color_Type)) { \
|
||||
Color *c = (Color*)v; self->overridden.name.rgb = c->color.rgb; self->overridden.name.type = COLOR_IS_RGB; \
|
||||
} else if (v == Py_None) { \
|
||||
if (!nullable) { PyErr_SetString(PyExc_ValueError, #name " cannot be set to None"); return -1; } \
|
||||
self->overridden.name.type = COLOR_IS_SPECIAL; self->overridden.name.rgb = 0; \
|
||||
} \
|
||||
self->dirty = true; return 0; \
|
||||
}
|
||||
|
||||
CGETSET(default_fg)
|
||||
CGETSET(default_bg)
|
||||
CGETSET(cursor_color)
|
||||
CGETSET(cursor_text_color)
|
||||
CGETSET(highlight_fg)
|
||||
CGETSET(highlight_bg)
|
||||
CGETSET(visual_bell_color)
|
||||
CGETSET(default_fg, false)
|
||||
CGETSET(default_bg, false)
|
||||
CGETSET(cursor_color, true)
|
||||
CGETSET(cursor_text_color, true)
|
||||
CGETSET(highlight_fg, true)
|
||||
CGETSET(highlight_bg, true)
|
||||
CGETSET(visual_bell_color, true)
|
||||
CGETSET(second_transparent_bg, true)
|
||||
#undef CGETSET
|
||||
|
||||
static PyGetSetDef cp_getsetters[] = {
|
||||
|
|
@ -431,6 +488,7 @@ static PyGetSetDef cp_getsetters[] = {
|
|||
GETSET(highlight_fg)
|
||||
GETSET(highlight_bg)
|
||||
GETSET(visual_bell_color)
|
||||
GETSET(second_transparent_bg)
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
@ -439,15 +497,25 @@ static PyMemberDef cp_members[] = {
|
|||
{NULL}
|
||||
};
|
||||
|
||||
static PyObject*
|
||||
reload_from_opts(ColorProfile *self, PyObject *args UNUSED) {
|
||||
PyObject *opts = global_state.options_object;
|
||||
if (!PyArg_ParseTuple(args, "|O", &opts)) return NULL;
|
||||
self->dirty = true;
|
||||
if (!set_configured_colors(self, opts)) return NULL;
|
||||
if (!set_mark_colors(self, opts)) return NULL;
|
||||
if (!set_colortable(self, opts)) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef cp_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)
|
||||
METHOD(set_color, METH_VARARGS)
|
||||
METHOD(set_configured_colors, METH_VARARGS)
|
||||
METHODB(reload_from_opts, METH_VARARGS),
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
@ -466,19 +534,21 @@ PyTypeObject ColorProfile_Type = {
|
|||
};
|
||||
// }}}
|
||||
|
||||
|
||||
static PyObject *
|
||||
new_color(PyTypeObject *type, PyObject *args, PyObject *kwds) {
|
||||
static const char* kwlist[] = {"red", "green", "blue", "alpha", NULL};
|
||||
Color *self;
|
||||
unsigned char r = 0, g = 0, b = 0, a = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|BBBB", (char**)kwlist, &r, &g, &b, &a)) return NULL;
|
||||
|
||||
self = (Color *)type->tp_alloc(type, 0);
|
||||
static Color*
|
||||
alloc_color(unsigned char r, unsigned char g, unsigned char b, unsigned a) {
|
||||
Color *self = (Color *)(&Color_Type)->tp_alloc(&Color_Type, 0);
|
||||
if (self != NULL) {
|
||||
self->color.r = r; self->color.g = g; self->color.b = b; self->color.a = a;
|
||||
}
|
||||
return (PyObject*) self;
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
new_color(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) {
|
||||
static const char* kwlist[] = {"red", "green", "blue", "alpha", NULL};
|
||||
unsigned char r = 0, g = 0, b = 0, a = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|BBBB", (char**)kwlist, &r, &g, &b, &a)) return NULL;
|
||||
return (PyObject*) alloc_color(r, g, b, a);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
|
@ -612,7 +682,6 @@ static PyMethodDef module_methods[] = {
|
|||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
int init_ColorProfile(PyObject *module) {\
|
||||
if (PyType_Ready(&ColorProfile_Type) < 0) return 0;
|
||||
if (PyModule_AddObject(module, "ColorProfile", (PyObject *)&ColorProfile_Type) != 0) return 0;
|
||||
|
|
|
|||
|
|
@ -435,10 +435,11 @@ def generate_c_conversion(loc: str, ctypes: List[Union[Option, MultiOption]]) ->
|
|||
return '\n'.join(preamble + ['', ''] + lines)
|
||||
|
||||
|
||||
def write_output(loc: str, defn: Definition) -> None:
|
||||
def write_output(loc: str, defn: Definition, extra_after_type_defn: str = '') -> None:
|
||||
cls, tc = generate_class(defn, loc)
|
||||
with open(os.path.join(*loc.split('.'), 'options', 'types.py'), 'w') as f:
|
||||
f.write(f'{cls}\n')
|
||||
f.write(extra_after_type_defn)
|
||||
with open(os.path.join(*loc.split('.'), 'options', 'parse.py'), 'w') as f:
|
||||
f.write(f'{tc}\n')
|
||||
ctypes = []
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@ def option_names_for_completion() -> Tuple[str, ...]:
|
|||
return option_names
|
||||
|
||||
|
||||
def build_ansi_color_table(opts: Optional[Options] = None) -> int:
|
||||
if opts is None:
|
||||
opts = defaults
|
||||
addr, length = opts.color_table.buffer_info()
|
||||
if length != 256 or opts.color_table.typecode != 'L':
|
||||
raise TypeError(f'The color table has incorrect size length: {length} typecode: {opts.color_table.typecode}')
|
||||
return addr
|
||||
|
||||
|
||||
def atomic_save(data: bytes, path: str) -> None:
|
||||
import shutil
|
||||
import tempfile
|
||||
|
|
|
|||
|
|
@ -319,22 +319,15 @@ typedef union DynamicColor {
|
|||
} DynamicColor;
|
||||
|
||||
typedef struct {
|
||||
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg, visual_bell_color;
|
||||
DynamicColor default_fg, default_bg, cursor_color, cursor_text_color, highlight_fg, highlight_bg, visual_bell_color, second_transparent_bg;
|
||||
} DynamicColors;
|
||||
|
||||
|
||||
typedef struct {
|
||||
DynamicColors dynamic_colors;
|
||||
uint32_t color_table[256];
|
||||
} ColorStackEntry;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
bool dirty;
|
||||
uint32_t color_table[256];
|
||||
uint32_t orig_color_table[256];
|
||||
ColorStackEntry *color_stack;
|
||||
uint32_t color_table[256], orig_color_table[256];
|
||||
struct { DynamicColors dynamic_colors; uint32_t color_table[256]; } *color_stack;
|
||||
unsigned int color_stack_idx, color_stack_sz;
|
||||
DynamicColors configured, overridden;
|
||||
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1];
|
||||
|
|
@ -389,7 +382,6 @@ LineBuf* alloc_linebuf(unsigned int, unsigned int);
|
|||
HistoryBuf* alloc_historybuf(unsigned int, unsigned int, unsigned int);
|
||||
ColorProfile* alloc_color_profile(void);
|
||||
void copy_color_profile(ColorProfile*, ColorProfile*);
|
||||
PyObject* create_256_color_table(void);
|
||||
PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
|
||||
PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
|
||||
void cursor_reset(Cursor*);
|
||||
|
|
|
|||
|
|
@ -755,8 +755,49 @@ class Color:
|
|||
|
||||
class ColorProfile:
|
||||
|
||||
default_fg: int
|
||||
default_bg: int
|
||||
# The dynamic color properties return the current color value. Use delattr
|
||||
# to reset them to configured value.
|
||||
@property
|
||||
def default_fg(self) -> Color: ...
|
||||
@default_fg.setter
|
||||
def default_fg(self, val: Union[int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def default_bg(self) -> Color: ...
|
||||
@default_bg.setter
|
||||
def default_bg(self, val: Union[int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def cursor_color(self) -> Optional[Color]: ...
|
||||
@cursor_color.setter
|
||||
def cursor_color(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def cursor_text_color(self) -> Optional[Color]: ...
|
||||
@cursor_text_color.setter
|
||||
def cursor_text_color(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def highlight_fg(self) -> Optional[Color]: ...
|
||||
@highlight_fg.setter
|
||||
def highlight_fg(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def highlight_bg(self) -> Optional[Color]: ...
|
||||
@highlight_bg.setter
|
||||
def highlight_bg(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def visual_bell_color(self) -> Optional[Color]: ...
|
||||
@visual_bell_color.setter
|
||||
def visual_bell_color(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
@property
|
||||
def second_transparent_bg(self) -> Optional[Color]: ...
|
||||
@second_transparent_bg.setter
|
||||
def second_transparent_bg(self, val: Union[None|int|Color]) -> None: ...
|
||||
|
||||
def __init__(self, opts: Optional[Options] = None): ...
|
||||
|
||||
def as_dict(self) -> Dict[str, Optional[int]]:
|
||||
pass
|
||||
|
|
@ -773,13 +814,7 @@ class ColorProfile:
|
|||
def reset_color(self, num: int) -> None:
|
||||
pass
|
||||
|
||||
def update_ansi_color_table(self, val: int) -> None:
|
||||
pass
|
||||
|
||||
def set_configured_colors(
|
||||
self, fg: int, bg: int, cursor: int = 0, cursor_text: int = 0, highlight_fg: int = 0, highlight_bg: int = 0, visual_bell_color: int = 0
|
||||
) -> None:
|
||||
pass
|
||||
def reload_from_opts(self, opts: Optional[Options] = None) -> None: ...
|
||||
|
||||
|
||||
def patch_color_profiles(
|
||||
|
|
|
|||
|
|
@ -1471,7 +1471,8 @@ theme with a background color in your editor, it will not be rendered as
|
|||
transparent. Instead you should change the default background color in your
|
||||
kitty config and not use a background color in the editor color scheme. Or use
|
||||
the escape codes to set the terminals default colors in a shell script to
|
||||
launch your editor. Be aware that using a value less than 1.0 is a (possibly
|
||||
launch your editor. See also :opt:`second_transparent_bg`.
|
||||
Be aware that using a value less than 1.0 is a (possibly
|
||||
significant) performance hit. When using a low value for this setting, it is
|
||||
desirable that you set the :opt:`background` color to a color the matches the
|
||||
general color of the desktop background, for best text rendering. If you want
|
||||
|
|
@ -1516,6 +1517,13 @@ opt('background_image_linear', 'no',
|
|||
long_text='When background image is scaled, whether linear interpolation should be used.'
|
||||
)
|
||||
|
||||
opt('second_transparent_bg', 'none', option_type='to_color_or_none', long_text='''
|
||||
When the background color matches this color, :opt:`background_opacity` is applied to it
|
||||
to render it as semi-transparent, just as for colors matching the background color.
|
||||
Useful, in more complex UIs like editors where you could want more than a single background color
|
||||
to be rendered as transparent.
|
||||
''')
|
||||
|
||||
opt('dynamic_background_opacity', 'no',
|
||||
option_type='to_bool', ctype='bool',
|
||||
long_text='''
|
||||
|
|
@ -1651,32 +1659,32 @@ opt('color15', '#ffffff',
|
|||
)
|
||||
|
||||
opt('mark1_foreground', 'black',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 1'
|
||||
)
|
||||
|
||||
opt('mark1_background', '#98d3cb',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 1 (light steel blue)'
|
||||
)
|
||||
|
||||
opt('mark2_foreground', 'black',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 2'
|
||||
)
|
||||
|
||||
opt('mark2_background', '#f2dcd3',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 1 (beige)'
|
||||
)
|
||||
|
||||
opt('mark3_foreground', 'black',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 3'
|
||||
)
|
||||
|
||||
opt('mark3_background', '#f274bc',
|
||||
option_type='to_color', ctype='color_as_int',
|
||||
option_type='to_color',
|
||||
long_text='Color for marks of type 3 (violet)'
|
||||
)
|
||||
|
||||
|
|
|
|||
3
kitty/options/parse.py
generated
3
kitty/options/parse.py
generated
|
|
@ -1189,6 +1189,9 @@ class Parser:
|
|||
def scrollback_pager_history_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['scrollback_pager_history_size'] = scrollback_pager_history_size(val)
|
||||
|
||||
def second_transparent_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['second_transparent_bg'] = to_color_or_none(val)
|
||||
|
||||
def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['select_by_word_characters'] = str(val)
|
||||
|
||||
|
|
|
|||
90
kitty/options/to-c-generated.h
generated
90
kitty/options/to-c-generated.h
generated
|
|
@ -902,84 +902,6 @@ convert_from_opts_dim_opacity(PyObject *py_opts, Options *opts) {
|
|||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark1_foreground(PyObject *val, Options *opts) {
|
||||
opts->mark1_foreground = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark1_foreground(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark1_foreground");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark1_foreground(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark1_background(PyObject *val, Options *opts) {
|
||||
opts->mark1_background = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark1_background(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark1_background");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark1_background(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark2_foreground(PyObject *val, Options *opts) {
|
||||
opts->mark2_foreground = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark2_foreground(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark2_foreground");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark2_foreground(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark2_background(PyObject *val, Options *opts) {
|
||||
opts->mark2_background = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark2_background(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark2_background");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark2_background(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark3_foreground(PyObject *val, Options *opts) {
|
||||
opts->mark3_foreground = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark3_foreground(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark3_foreground");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark3_foreground(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_mark3_background(PyObject *val, Options *opts) {
|
||||
opts->mark3_background = color_as_int(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_mark3_background(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "mark3_background");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_mark3_background(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_close_on_child_death(PyObject *val, Options *opts) {
|
||||
opts->close_on_child_death = PyObject_IsTrue(val);
|
||||
|
|
@ -1315,18 +1237,6 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
|
|||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_dim_opacity(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark1_foreground(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark1_background(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark2_foreground(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark2_background(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark3_foreground(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_mark3_background(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_close_on_child_death(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_allow_hyperlinks(py_opts, opts);
|
||||
|
|
|
|||
14
kitty/options/types.py
generated
14
kitty/options/types.py
generated
|
|
@ -408,6 +408,7 @@ option_names = ( # {{{
|
|||
'scrollback_lines',
|
||||
'scrollback_pager',
|
||||
'scrollback_pager_history_size',
|
||||
'second_transparent_bg',
|
||||
'select_by_word_characters',
|
||||
'select_by_word_characters_forward',
|
||||
'selection_background',
|
||||
|
|
@ -572,6 +573,7 @@ class Options:
|
|||
scrollback_lines: int = 2000
|
||||
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
|
||||
scrollback_pager_history_size: int = 0
|
||||
second_transparent_bg: typing.Optional[kitty.fast_data_types.Color] = None
|
||||
select_by_word_characters: str = '@-./_~?&=%+#'
|
||||
select_by_word_characters_forward: str = ''
|
||||
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
|
||||
|
|
@ -1022,3 +1024,15 @@ defaults.mouse_map = [
|
|||
# show_clicked_cmd_output_ungrabbed
|
||||
MouseMapping(button=1, mods=5, definition='mouse_show_command_output'),
|
||||
]
|
||||
|
||||
nullable_colors = frozenset({
|
||||
'cursor'
|
||||
'cursor_text_color'
|
||||
'visual_bell_color'
|
||||
'active_border_color'
|
||||
'tab_bar_background'
|
||||
'tab_bar_margin_color'
|
||||
'second_transparent_bg'
|
||||
'selection_foreground'
|
||||
'selection_background'
|
||||
})
|
||||
|
|
@ -27,22 +27,8 @@ if TYPE_CHECKING:
|
|||
from kitty.cli_stub import SetColorsRCOptions as CLIOptions
|
||||
|
||||
|
||||
nullable_colors = (
|
||||
# generated by gen-config.py DO NOT edit
|
||||
# NULLABLE_COLORS_START
|
||||
'active_border_color',
|
||||
'cursor',
|
||||
'cursor_text_color',
|
||||
'selection_background',
|
||||
'selection_foreground',
|
||||
'tab_bar_background',
|
||||
'tab_bar_margin_color',
|
||||
'visual_bell_color',
|
||||
# NULLABLE_COLORS_END
|
||||
)
|
||||
|
||||
|
||||
def parse_colors(args: Iterable[str]) -> Dict[str, Optional[int]]:
|
||||
from kitty.options.types import nullable_colors
|
||||
colors: Dict[str, Optional[Color]] = {}
|
||||
nullable_color_map: Dict[str, Optional[int]] = {}
|
||||
for spec in args:
|
||||
|
|
@ -121,8 +107,7 @@ this option, any color arguments are ignored and :option:`kitten @ set-colors --
|
|||
windows = self.windows_for_payload(boss, window, payload_get)
|
||||
colors: Dict[str, Optional[int]] = payload_get('colors')
|
||||
if payload_get('reset'):
|
||||
colors = {k: int(v) for k, v in boss.startup_colors.items()}
|
||||
colors['cursor_text_color'] = None if boss.startup_cursor_text_color is None else int(boss.startup_cursor_text_color)
|
||||
colors = {k: None if v is None else int(v) for k, v in boss.color_settings_at_startup.items()}
|
||||
profiles = tuple(w.screen.color_profile for w in windows if w)
|
||||
patch_color_profiles(colors, profiles, payload_get('configured'))
|
||||
boss.patch_colors(colors, payload_get('configured'))
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
|
|||
struct GPUCellRenderData {
|
||||
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, use_cell_bg_for_selection_fg, use_cell_fg_for_selection_color, use_cell_for_selection_bg;
|
||||
|
||||
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted;
|
||||
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_fg, cursor_bg, url_color, url_style, inverted, second_transparent_bg;
|
||||
|
||||
GLuint xnum, ynum, cursor_fg_sprite_idx;
|
||||
GLfloat cursor_x, cursor_y, cursor_w, cursor_opacity;
|
||||
|
|
@ -320,6 +320,7 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
|
|||
rd->use_cell_bg_for_selection_fg = 0.f; rd->use_cell_fg_for_selection_color = 0.f;
|
||||
}
|
||||
rd->use_cell_for_selection_bg = IS_SPECIAL_COLOR(highlight_bg) ? 1. : 0.;
|
||||
rd->second_transparent_bg = IS_SPECIAL_COLOR(second_transparent_bg) ? rd->default_bg : COLOR(second_transparent_bg);
|
||||
// Cursor position
|
||||
enum { BLOCK_IDX = 0, BEAM_IDX = NUM_UNDERLINE_STYLES + 3, UNDERLINE_IDX = NUM_UNDERLINE_STYLES + 4, UNFOCUSED_IDX = NUM_UNDERLINE_STYLES + 5 };
|
||||
Line *line_for_cursor = NULL;
|
||||
|
|
|
|||
|
|
@ -719,15 +719,14 @@ PYWRAP1(handle_for_window_id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject* options_object = NULL;
|
||||
|
||||
PYWRAP0(get_options) {
|
||||
if (!options_object) {
|
||||
if (!global_state.options_object) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Must call set_options() before using get_options()");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(options_object);
|
||||
return options_object;
|
||||
Py_INCREF(global_state.options_object);
|
||||
return global_state.options_object;
|
||||
}
|
||||
|
||||
PYWRAP1(set_options) {
|
||||
|
|
@ -735,7 +734,7 @@ PYWRAP1(set_options) {
|
|||
int is_wayland = 0, debug_rendering = 0, debug_font_fallback = 0;
|
||||
PA("O|ppp", &opts, &is_wayland, &debug_rendering, &debug_font_fallback);
|
||||
if (opts == Py_None) {
|
||||
Py_CLEAR(options_object);
|
||||
Py_CLEAR(global_state.options_object);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
global_state.is_wayland = is_wayland ? true : false;
|
||||
|
|
@ -746,8 +745,8 @@ PYWRAP1(set_options) {
|
|||
global_state.debug_rendering = debug_rendering ? true : false;
|
||||
global_state.debug_font_fallback = debug_font_fallback ? true : false;
|
||||
if (!convert_opts_from_python_opts(opts, &global_state.opts)) return NULL;
|
||||
options_object = opts;
|
||||
Py_INCREF(options_object);
|
||||
global_state.options_object = opts;
|
||||
Py_INCREF(global_state.options_object);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -1159,8 +1158,6 @@ PYWRAP1(patch_global_colors) {
|
|||
P(active_border_color); P(inactive_border_color); P(bell_border_color); P(tab_bar_background); P(tab_bar_margin_color);
|
||||
if (configured) {
|
||||
P(background); P(url_color);
|
||||
P(mark1_background); P(mark1_foreground); P(mark2_background); P(mark2_foreground);
|
||||
P(mark3_background); P(mark3_foreground);
|
||||
}
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
|
|
@ -1461,7 +1458,7 @@ finalize(void) {
|
|||
#define F(x) free(OPT(x)); OPT(x) = NULL;
|
||||
F(background_image); F(bell_path); F(bell_theme); F(default_window_logo);
|
||||
#undef F
|
||||
Py_CLEAR(options_object);
|
||||
Py_CLEAR(global_state.options_object);
|
||||
free_animation(OPT(animation.cursor));
|
||||
free_animation(OPT(animation.visual_bell));
|
||||
// we leak the texture here since it is not guaranteed
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ typedef struct {
|
|||
char_type *select_by_word_characters;
|
||||
char_type *select_by_word_characters_forward;
|
||||
color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color, tab_bar_background, tab_bar_margin_color;
|
||||
color_type mark1_foreground, mark1_background, mark2_foreground, mark2_background, mark3_foreground, mark3_background;
|
||||
monotonic_t repaint_delay, input_delay;
|
||||
bool focus_follows_mouse;
|
||||
unsigned int hide_window_decorations;
|
||||
|
|
@ -307,6 +306,7 @@ typedef struct {
|
|||
bool redirect_mouse_handling;
|
||||
WindowLogoTable *all_window_logos;
|
||||
int gl_version;
|
||||
PyObject *options_object;
|
||||
} GlobalState;
|
||||
|
||||
extern GlobalState global_state;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ from typing import (
|
|||
)
|
||||
|
||||
from .borders import Border, BorderColor
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import config_dir
|
||||
from .fast_data_types import (
|
||||
DECAWM,
|
||||
|
|
@ -495,11 +494,8 @@ class TabBar:
|
|||
self.screen = s = Screen(None, 1, 10, 0, self.cell_width, cell_height)
|
||||
else:
|
||||
s = self.screen
|
||||
s.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
s.color_profile.set_configured_colors(
|
||||
color_as_int(opts.inactive_tab_foreground),
|
||||
color_as_int(opts.tab_bar_background or opts.background)
|
||||
)
|
||||
s.color_profile.default_fg = opts.inactive_tab_foreground
|
||||
s.color_profile.default_bg = opts.tab_bar_background or opts.background
|
||||
sep = opts.tab_separator
|
||||
self.trailing_spaces = self.leading_spaces = 0
|
||||
while sep and sep[0] == ' ':
|
||||
|
|
@ -575,8 +571,9 @@ class TabBar:
|
|||
ifg = color_from_int(fg)
|
||||
if ifg is not None:
|
||||
self.draw_data = self.draw_data._replace(inactive_fg=ifg)
|
||||
self.screen.color_profile.set_configured_colors(fg, bg)
|
||||
self.screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
self.screen.color_profile.reload_from_opts()
|
||||
self.screen.color_profile.default_fg = color_from_int(fg)
|
||||
self.screen.color_profile.default_bg = color_from_int(bg)
|
||||
|
||||
@property
|
||||
def current_colors(self) -> Dict[str, Color]:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ from typing import (
|
|||
from .child import ProcessDesc
|
||||
from .cli_stub import CLIOptions
|
||||
from .clipboard import ClipboardRequestManager, set_clipboard_string
|
||||
from .config import build_ansi_color_table
|
||||
from .constants import (
|
||||
appname,
|
||||
clear_handled_signals,
|
||||
|
|
@ -98,7 +97,6 @@ from .notify import (
|
|||
notify_with_command,
|
||||
sanitize_identifier_pat,
|
||||
)
|
||||
from .options.types import Options
|
||||
from .rgb import to_color
|
||||
from .terminfo import get_capabilities
|
||||
from .types import MouseEvent, OverlayType, WindowGeometry, ac, run_once
|
||||
|
|
@ -407,19 +405,6 @@ def as_text(
|
|||
|
||||
|
||||
|
||||
def setup_colors(screen: Screen, opts: Options) -> None:
|
||||
screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
|
||||
def s(c: Optional[Color]) -> int:
|
||||
return 0 if c is None else (0xff000000 | int(c))
|
||||
screen.color_profile.set_configured_colors(
|
||||
s(opts.foreground), s(opts.background),
|
||||
s(opts.cursor), s(opts.cursor_text_color),
|
||||
s(opts.selection_foreground), s(opts.selection_background),
|
||||
s(opts.visual_bell_color)
|
||||
)
|
||||
|
||||
|
||||
@run_once
|
||||
def load_paste_filter() -> Callable[[str], str]:
|
||||
import runpy
|
||||
|
|
@ -605,8 +590,6 @@ class Window:
|
|||
self.screen: Screen = Screen(self, 24, 80, opts.scrollback_lines, cell_width, cell_height, self.id)
|
||||
if copy_colors_from is not None:
|
||||
self.screen.copy_colors_from(copy_colors_from.screen)
|
||||
else:
|
||||
setup_colors(self.screen, opts)
|
||||
self.remote_control_passwords = remote_control_passwords
|
||||
self.allow_remote_control = allow_remote_control
|
||||
|
||||
|
|
@ -681,9 +664,8 @@ class Window:
|
|||
return int(val)
|
||||
|
||||
def apply_options(self, is_active: bool) -> None:
|
||||
opts = get_options()
|
||||
self.update_effective_padding()
|
||||
setup_colors(self.screen, opts)
|
||||
self.screen.color_profile.reload_from_opts()
|
||||
|
||||
@property
|
||||
def title(self) -> str:
|
||||
|
|
@ -1188,33 +1170,12 @@ class Window:
|
|||
tab.relayout_borders()
|
||||
tab.on_bell(self)
|
||||
|
||||
def change_colors(self, changes: Dict[DynamicColor, Optional[str]]) -> None:
|
||||
dirtied = default_bg_changed = False
|
||||
|
||||
def item(raw: Optional[str]) -> int:
|
||||
if raw is None:
|
||||
return 0
|
||||
v = to_color(raw)
|
||||
if v is None:
|
||||
return 0
|
||||
return 0xff000000 | int(v)
|
||||
|
||||
for which, val_ in changes.items():
|
||||
val = item(val_)
|
||||
dirtied = True
|
||||
setattr(self.screen.color_profile, which.name, val)
|
||||
if which.name == 'default_bg':
|
||||
default_bg_changed = True
|
||||
if dirtied:
|
||||
self.screen.mark_as_dirty()
|
||||
if default_bg_changed:
|
||||
get_boss().default_bg_changed_for(self.id)
|
||||
|
||||
def color_profile_popped(self, bg_changed: bool) -> None:
|
||||
if bg_changed:
|
||||
get_boss().default_bg_changed_for(self.id)
|
||||
|
||||
def report_color(self, code: str, r: int, g: int, b: int) -> None:
|
||||
def report_color(self, code: str, col: Color) -> None:
|
||||
r, g, b = col.red, col.green, col.blue
|
||||
r |= r << 8
|
||||
g |= g << 8
|
||||
b |= b << 8
|
||||
|
|
@ -1236,19 +1197,33 @@ class Window:
|
|||
ret = set_pointer_shape(self.screen, value, self.os_window_id)
|
||||
if ret:
|
||||
self.screen.send_escape_code_to_child(ESC_OSC, '22:' + ret)
|
||||
color_changes: Dict[DynamicColor, Optional[str]] = {}
|
||||
|
||||
dirtied = default_bg_changed = False
|
||||
def change(which: DynamicColor, val: str) -> None:
|
||||
nonlocal dirtied, default_bg_changed
|
||||
dirtied = True
|
||||
if which.name == 'default_bg':
|
||||
default_bg_changed = True
|
||||
v = to_color(val) if val else None
|
||||
if v is None:
|
||||
delattr(self.screen.color_profile, which.name)
|
||||
else:
|
||||
setattr(self.screen.color_profile, which.name, v)
|
||||
|
||||
for val in value.split(';'):
|
||||
w = DYNAMIC_COLOR_CODES.get(code)
|
||||
if w is not None:
|
||||
if val == '?':
|
||||
col = getattr(self.screen.color_profile, w.name)
|
||||
self.report_color(str(code), col >> 16, (col >> 8) & 0xff, col & 0xff)
|
||||
col = getattr(self.screen.color_profile, w.name) or Color()
|
||||
self.report_color(str(code), col)
|
||||
else:
|
||||
q = None if code >= 100 else val
|
||||
color_changes[w] = q
|
||||
q = '' if code >= 100 else val
|
||||
change(w, q)
|
||||
code += 1
|
||||
if color_changes:
|
||||
self.change_colors(color_changes)
|
||||
if dirtied:
|
||||
self.screen.mark_as_dirty()
|
||||
if default_bg_changed:
|
||||
get_boss().default_bg_changed_for(self.id)
|
||||
|
||||
def set_color_table_color(self, code: int, bvalue: Optional[memoryview] = None) -> None:
|
||||
value = str(bvalue or b'', 'utf-8', 'replace')
|
||||
|
|
@ -1259,7 +1234,7 @@ class Window:
|
|||
if val is None: # color query
|
||||
qc = self.screen.color_profile.as_color((c << 8) | 1)
|
||||
assert qc is not None
|
||||
self.report_color(f'4;{c}', qc.red, qc.green, qc.blue)
|
||||
self.report_color(f'4;{c}', qc)
|
||||
else:
|
||||
changed = True
|
||||
cp.set_color(c, val)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from contextlib import suppress
|
|||
from itertools import count
|
||||
from typing import Any, Deque, Dict, Iterator, List, Optional, Tuple, Union
|
||||
|
||||
from .fast_data_types import Color, get_options
|
||||
from .types import OverlayType, WindowGeometry
|
||||
from .typing import EdgeLiteral, TabType, WindowType
|
||||
|
||||
|
|
@ -120,23 +121,23 @@ class WindowGroup:
|
|||
w.set_geometry(geom)
|
||||
|
||||
@property
|
||||
def default_bg(self) -> int:
|
||||
def default_bg(self) -> Color:
|
||||
if self.windows:
|
||||
w: WindowType = self.windows[-1]
|
||||
return w.screen.color_profile.default_bg
|
||||
return 0
|
||||
w = self.windows[-1]
|
||||
return w.screen.color_profile.default_bg or get_options().background
|
||||
return get_options().background
|
||||
|
||||
@property
|
||||
def geometry(self) -> Optional[WindowGeometry]:
|
||||
if self.windows:
|
||||
w: WindowType = self.windows[-1]
|
||||
w = self.windows[-1]
|
||||
return w.geometry
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_visible_in_layout(self) -> bool:
|
||||
if self.windows:
|
||||
w: WindowType = self.windows[-1]
|
||||
w = self.windows[-1]
|
||||
return w.is_visible_in_layout
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import os
|
|||
import sys
|
||||
import tempfile
|
||||
|
||||
from kitty.config import build_ansi_color_table, defaults
|
||||
from kitty.config import defaults
|
||||
from kitty.fast_data_types import (
|
||||
Color,
|
||||
ColorProfile,
|
||||
|
|
@ -477,8 +477,7 @@ class TestDataTypes(BaseTest):
|
|||
'h://a\u0430b.com/El%20Ni%C3%B1o/'), 'h://xn--ab-7kc.com/El Niño/')
|
||||
|
||||
def test_color_profile(self):
|
||||
c = ColorProfile()
|
||||
c.update_ansi_color_table(build_ansi_color_table())
|
||||
c = ColorProfile(defaults)
|
||||
for i in range(8):
|
||||
col = getattr(defaults, f'color{i}')
|
||||
self.ae(c.as_color(i << 8 | 1), col)
|
||||
|
|
|
|||
|
|
@ -15,14 +15,15 @@ import (
|
|||
var nullable_colors = map[string]bool{
|
||||
// generated by gen-config.py do not edit
|
||||
// NULLABLE_COLORS_START
|
||||
"active_border_color": true,
|
||||
"cursor": true,
|
||||
"cursor_text_color": true,
|
||||
"selection_background": true,
|
||||
"selection_foreground": true,
|
||||
"tab_bar_background": true,
|
||||
"tab_bar_margin_color": true,
|
||||
"visual_bell_color": true,
|
||||
"active_border_color": true,
|
||||
"cursor": true,
|
||||
"cursor_text_color": true,
|
||||
"second_transparent_bg": true,
|
||||
"selection_background": true,
|
||||
"selection_foreground": true,
|
||||
"tab_bar_background": true,
|
||||
"tab_bar_margin_color": true,
|
||||
"visual_bell_color": true,
|
||||
// NULLABLE_COLORS_END
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ var AllColorSettingNames = map[string]bool{ // {{{
|
|||
"mark2_foreground": true,
|
||||
"mark3_background": true,
|
||||
"mark3_foreground": true,
|
||||
"second_transparent_bg": true,
|
||||
"selection_background": true,
|
||||
"selection_foreground": true,
|
||||
"tab_bar_background": true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue