mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-11-11 09:52:13 +03:00
Use a more efficient representation of the color table on the Options object
This commit is contained in:
parent
2e71429b03
commit
79dd98b20e
@ -8,12 +8,17 @@ import pprint
|
||||
import re
|
||||
import textwrap
|
||||
from typing import (
|
||||
Any, Callable, Dict, List, Set, Tuple, Union, get_type_hints
|
||||
Any, Callable, Dict, Iterator, List, Set, Tuple, Union, get_type_hints
|
||||
)
|
||||
|
||||
from kitty.conf.types import Definition, MultiOption, Option, unset
|
||||
|
||||
|
||||
def chunks(lst: List, n: int) -> Iterator[List]:
|
||||
for i in range(0, len(lst), n):
|
||||
yield lst[i:i + n]
|
||||
|
||||
|
||||
def atoi(text: str) -> str:
|
||||
return f'{int(text):08d}' if text.isdigit() else text
|
||||
|
||||
@ -60,6 +65,7 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
|
||||
|
||||
is_mutiple_vars = {}
|
||||
option_names = set()
|
||||
color_table = list(map(str, range(256)))
|
||||
|
||||
def parser_function_declaration(option_name: str) -> None:
|
||||
t('')
|
||||
@ -93,6 +99,22 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
|
||||
choices[ename] = typ
|
||||
typ = ename
|
||||
func = str
|
||||
elif defn.has_color_table and option.is_color_table_color:
|
||||
func, typ = option_type_data(option)
|
||||
t(f' ans[{option.name!r}] = {func.__name__}(val)')
|
||||
tc_imports.add((func.__module__, func.__name__))
|
||||
cnum = int(option.name[5:])
|
||||
color_table[cnum] = '0x{:06x}'.format(func(option.defval_as_string).__int__())
|
||||
a('')
|
||||
a(' @property')
|
||||
a(f' def {option.name}(self) -> {typ}:')
|
||||
a(f' x = self.color_table[{cnum}]')
|
||||
a(f' return {typ}((x >> 16) & 255, (x >> 8) & 255, x & 255)')
|
||||
a('')
|
||||
a(f' @{option.name}.setter')
|
||||
a(f' def {option.name}(self, val: {typ}) -> None:')
|
||||
a(f' self.color_table[{cnum}] = val.__int__()')
|
||||
continue
|
||||
else:
|
||||
func, typ = option_type_data(option)
|
||||
try:
|
||||
@ -157,6 +179,13 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
|
||||
t(f' ans[{aname!r}].append(k)')
|
||||
tc_imports.add((func.__module__, func.__name__))
|
||||
|
||||
if defn.has_color_table:
|
||||
imports.add(('array', 'array'))
|
||||
a(' color_table: array = array("L", (')
|
||||
for grp in chunks(color_table, 8):
|
||||
a(' ' + ', '.join(grp) + ',')
|
||||
a(' ))')
|
||||
|
||||
a('')
|
||||
a(' def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:')
|
||||
a(' if options_dict is not None:')
|
||||
@ -297,7 +326,7 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
|
||||
s = '\n '.join(lines)
|
||||
s = f'(\n {s}\n)'
|
||||
a(f'from {mod} import {s}')
|
||||
if add_module_imports and mod not in seen_mods:
|
||||
if add_module_imports and mod not in seen_mods and mod != s:
|
||||
a(f'import {mod}')
|
||||
seen_mods.add(mod)
|
||||
|
||||
|
@ -92,11 +92,11 @@ alloc_color_profile() {
|
||||
static PyObject*
|
||||
update_ansi_color_table(ColorProfile *self, PyObject *val) {
|
||||
#define update_ansi_color_table_doc "Update the 256 basic colors"
|
||||
if (!PyList_Check(val)) { PyErr_SetString(PyExc_TypeError, "color table must be a list"); return NULL; }
|
||||
if (PyList_GET_SIZE(val) != arraysz(FG_BG_256)) { PyErr_SetString(PyExc_TypeError, "color table must have 256 items"); return NULL; }
|
||||
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] = PyLong_AsUnsignedLong(PyList_GET_ITEM(val, i));
|
||||
self->orig_color_table[i] = self->color_table[i];
|
||||
self->color_table[i] = color_table[i];
|
||||
self->orig_color_table[i] = color_table[i];
|
||||
}
|
||||
self->dirty = true;
|
||||
Py_RETURN_NONE;
|
||||
|
@ -165,6 +165,10 @@ class Option:
|
||||
def needs_coalescing(self) -> bool:
|
||||
return self.documented and not self.long_text
|
||||
|
||||
@property
|
||||
def is_color_table_color(self) -> bool:
|
||||
return self.name.startswith('color') and self.name[5:].isdigit()
|
||||
|
||||
def as_conf(self, commented: bool = False, level: int = 0, option_group: List['Option'] = []) -> List[str]:
|
||||
ans: List[str] = []
|
||||
a = ans.append
|
||||
@ -536,8 +540,9 @@ class Action:
|
||||
|
||||
class Definition:
|
||||
|
||||
def __init__(self, package: str, *actions: Action) -> None:
|
||||
def __init__(self, package: str, *actions: Action, has_color_table: bool = False) -> None:
|
||||
self.module_for_parsers = import_module(f'{package}.options.utils')
|
||||
self.has_color_table = has_color_table
|
||||
self.package = package
|
||||
self.coalesced_iterator_data = CoalescedIteratorData()
|
||||
self.root_group = Group('', '', self.coalesced_iterator_data)
|
||||
|
@ -25,17 +25,13 @@ def option_names_for_completion() -> Tuple[str, ...]:
|
||||
no_op_actions = frozenset({'noop', 'no-op', 'no_op'})
|
||||
|
||||
|
||||
def build_ansi_color_table(opts: Optional[Options] = None) -> List[int]:
|
||||
def build_ansi_color_table(opts: Optional[Options] = None) -> int:
|
||||
if opts is None:
|
||||
opts = defaults
|
||||
|
||||
def as_int(x: Tuple[int, int, int]) -> int:
|
||||
return (x[0] << 16) | (x[1] << 8) | x[2]
|
||||
|
||||
def col(i: int) -> int:
|
||||
return as_int(getattr(opts, 'color{}'.format(i)))
|
||||
|
||||
return list(map(col, range(256)))
|
||||
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:
|
||||
|
@ -633,7 +633,7 @@ class ColorProfile:
|
||||
def reset_color(self, num: int) -> None:
|
||||
pass
|
||||
|
||||
def update_ansi_color_table(self, val: List[int]) -> None:
|
||||
def update_ansi_color_table(self, val: int) -> None:
|
||||
pass
|
||||
|
||||
def set_configured_colors(
|
||||
|
@ -12,6 +12,7 @@ definition = Definition(
|
||||
Action('map', 'parse_map', {'keymap': 'KeyMap', 'sequence_map': 'SequenceMap'},
|
||||
['KeyDefinition', 'kitty.conf.utils.KeyAction', 'kitty.types.SingleKey']),
|
||||
Action('mouse_map', 'parse_mouse_map', {'mousemap': 'MouseMap'}, ['MouseMapping', 'kitty.conf.utils.KeyAction']),
|
||||
has_color_table=True,
|
||||
)
|
||||
definition.add_deprecation('deprecated_hide_window_decorations_aliases', 'x11_hide_window_decorations', 'macos_hide_titlebar')
|
||||
definition.add_deprecation('deprecated_macos_show_window_title_in_menubar_alias', 'macos_show_window_title_in_menubar')
|
||||
|
2613
kitty/options/types.py
generated
2613
kitty/options/types.py
generated
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Union
|
||||
|
||||
from kitty.config import parse_config
|
||||
from kitty.fast_data_types import patch_color_profiles
|
||||
from kitty.rgb import Color, color_as_int
|
||||
from kitty.rgb import Color
|
||||
|
||||
from .base import (
|
||||
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
|
||||
@ -28,8 +28,8 @@ def parse_colors(args: Iterable[str]) -> Tuple[Dict[str, int], Optional[Union[in
|
||||
with open(os.path.expanduser(spec), encoding='utf-8', errors='replace') as f:
|
||||
colors.update(parse_config(f))
|
||||
q = colors.pop('cursor_text_color', False)
|
||||
ctc = color_as_int(q) if isinstance(q, Color) else (False if q is False else None)
|
||||
return {k: color_as_int(v) for k, v in colors.items() if isinstance(v, Color)}, ctc
|
||||
ctc = int(q) if isinstance(q, Color) else (False if q is False else None)
|
||||
return {k: int(v) for k, v in colors.items() if isinstance(v, Color)}, ctc
|
||||
|
||||
|
||||
class SetColors(RemoteCommand):
|
||||
@ -92,11 +92,11 @@ this option, any color arguments are ignored and --configured and --all are impl
|
||||
colors = payload_get('colors')
|
||||
cursor_text_color = payload_get('cursor_text_color', missing=False)
|
||||
if payload_get('reset'):
|
||||
colors = {k: color_as_int(v) for k, v in boss.startup_colors.items()}
|
||||
colors = {k: int(v) for k, v in boss.startup_colors.items()}
|
||||
cursor_text_color = boss.startup_cursor_text_color
|
||||
profiles = tuple(w.screen.color_profile for w in windows)
|
||||
if isinstance(cursor_text_color, (tuple, list, Color)):
|
||||
cursor_text_color = color_as_int(Color(*cursor_text_color))
|
||||
cursor_text_color = int(Color(*cursor_text_color))
|
||||
patch_color_profiles(colors, cursor_text_color, profiles, payload_get('configured'))
|
||||
boss.patch_colors(colors, cursor_text_color, payload_get('configured'))
|
||||
default_bg_changed = 'background' in colors
|
||||
|
3
kitty/rgb.py
generated
3
kitty/rgb.py
generated
@ -22,6 +22,9 @@ class Color(NamedTuple):
|
||||
a, b = b, a
|
||||
return (a + 0.05) / (b + 0.05)
|
||||
|
||||
def __int__(self) -> int:
|
||||
return self.red << 16 | self.green << 8 | self.blue
|
||||
|
||||
|
||||
def alpha_blend_channel(top_color: int, bottom_color: int, alpha: float) -> int:
|
||||
return int(alpha * top_color + (1 - alpha) * bottom_color)
|
||||
|
Loading…
Reference in New Issue
Block a user