diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 504a7bd7f..6d52d970f 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -807,6 +807,12 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int * if (send_cell_data_to_gpu(WD.vao_idx, WD.screen, os_window)) needs_render = true; if (WD.screen->start_visual_bell_at != 0) needs_render = true; } + // Prepare pane title bar screen data for GPU + if (w->visible && w->pane_title_render_data.screen) { + CursorRenderInfo *cri = &w->pane_title_render_data.screen->cursor_render_info; + zero_at_ptr(cri); + if (send_cell_data_to_gpu(w->pane_title_render_data.vao_idx, w->pane_title_render_data.screen, os_window)) needs_render = true; + } } return needs_render || was_previously_rendered_with_layers != os_window->needs_layers; } @@ -868,6 +874,15 @@ render_prepared_os_window(OSWindow *os_window, unsigned int active_window_id, co if (WD.screen->start_visual_bell_at != 0) set_maximum_wait(ANIMATION_SAMPLE_WAIT); } } + // Draw pane title bars + for (unsigned int i = 0; i < tab->num_windows; i++) { + Window *w = tab->windows + i; + if (w->visible && w->pane_title_render_data.screen && + w->pane_title_render_data.geometry.right > w->pane_title_render_data.geometry.left && + w->pane_title_render_data.geometry.bottom > w->pane_title_render_data.geometry.top) { + draw_cells(&w->pane_title_render_data, os_window, i == tab->active_window, true, false, NULL); + } + } setup_os_window_for_rendering(os_window, tab, active_window, false); if (global_state.thumbnail_callback.os_window == os_window->id) { thumbnail_callback(os_window); diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index d826597e7..c3a0eec68 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1404,6 +1404,13 @@ def set_tab_bar_render_data( pass +def set_pane_title_bar_render_data( + os_window_id: int, tab_id: int, window_id: int, screen: Screen, + left: int, top: int, right: int, bottom: int +) -> None: + pass + + def set_window_render_data( os_window_id: int, tab_id: int, window_id: int, screen: Screen, left: int, top: int, right: int, bottom: int, diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 62d0098dd..667fdfdf9 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -368,6 +368,26 @@ class Layout: self.update_visibility(all_windows) self.blank_rects = [] self.do_layout(all_windows) + self._apply_pane_title_bars(all_windows) + + def _apply_pane_title_bars(self, all_windows: WindowList) -> None: + opts = get_options() + position = opts.pane_title_bar + if position == 'none': + return + visible_groups = list(all_windows.iter_all_layoutable_groups(only_visible=True)) + if len(visible_groups) < 2: + return + ch = lgd.cell_height + for wg in visible_groups: + geom = wg.geometry + if geom is None: + continue + if position == 'top': + new_geom = geom._replace(top=geom.top + ch, ynum=max(1, geom.ynum - 1)) + else: + new_geom = geom._replace(bottom=geom.bottom - ch, ynum=max(1, geom.ynum - 1)) + wg.set_geometry(new_geom) def layout_single_window_group(self, wg: WindowGroup, add_blank_rects: bool = True) -> None: bw = 1 if self.must_draw_borders else 0 diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 0c24ca30a..409e619de 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -1466,6 +1466,59 @@ dragging of borders. Note that because kitty uses layouts, dragging borders does actually resize the window itself, but instead, the layout row/column/slot, which can result in multiple windows getting resized. ''') + +opt('pane_title_bar', 'none', + choices=('none', 'top', 'bottom'), + long_text=''' +Show a title bar for each window/pane when there are multiple windows in a tab. +The title bar displays the window title and is hidden when only a single window +is visible. The value controls the position of the title bar relative to the +window content. Set to :code:`none` to disable. +''' + ) + +opt('pane_title_template', '"{title}"', + option_type='tab_title_template', + long_text=''' +A template to render the pane title bar text. Uses the same template syntax as +:opt:`tab_title_template`. Available variables include: :code:`{title}`, +:code:`{index}`, :code:`{layout_name}`, :code:`{num_windows}`, +:code:`{num_window_groups}`, :code:`{tab.active_wd}`, etc. +''' + ) + +opt('active_pane_title_template', 'none', + option_type='tab_title_template', + long_text=''' +Template to use for the active pane title bar. If not set (the value +:code:`none`), the :opt:`pane_title_template` is used. +''' + ) + +opt('pane_title_bar_active_fg', '#000000', + option_type='to_color', + long_text='Foreground color for the active pane title bar.' + ) + +opt('pane_title_bar_active_bg', '#00ff00', + option_type='to_color', + long_text='Background color for the active pane title bar.' + ) + +opt('pane_title_bar_inactive_fg', '#cccccc', + option_type='to_color', + long_text='Foreground color for inactive pane title bars.' + ) + +opt('pane_title_bar_inactive_bg', '#333333', + option_type='to_color', + long_text='Background color for inactive pane title bars.' + ) + +opt('pane_title_bar_align', 'center', + choices=('left', 'center', 'right'), + long_text='Horizontal alignment of the text in pane title bars.' + ) egr() # }}} diff --git a/kitty/options/parse.py b/kitty/options/parse.py index ff7e3f0aa..8f8249ba3 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -36,6 +36,9 @@ class Parser: def active_border_color(self, val: str, ans: dict[str, typing.Any]) -> None: ans['active_border_color'] = to_color_or_none(val) + def active_pane_title_template(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['active_pane_title_template'] = tab_title_template(val) + def active_tab_background(self, val: str, ans: dict[str, typing.Any]) -> None: ans['active_tab_background'] = to_color(val) @@ -1165,6 +1168,37 @@ class Parser: def open_url_with(self, val: str, ans: dict[str, typing.Any]) -> None: ans['open_url_with'] = to_cmdline(val) + def pane_title_bar(self, val: str, ans: dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_pane_title_bar: + raise ValueError(f"The value {val} is not a valid choice for pane_title_bar") + ans["pane_title_bar"] = val + + choices_for_pane_title_bar = frozenset(('none', 'top', 'bottom')) + + def pane_title_bar_active_bg(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['pane_title_bar_active_bg'] = to_color(val) + + def pane_title_bar_active_fg(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['pane_title_bar_active_fg'] = to_color(val) + + def pane_title_bar_align(self, val: str, ans: dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_pane_title_bar_align: + raise ValueError(f"The value {val} is not a valid choice for pane_title_bar_align") + ans["pane_title_bar_align"] = val + + choices_for_pane_title_bar_align = frozenset(('left', 'center', 'right')) + + def pane_title_bar_inactive_bg(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['pane_title_bar_inactive_bg'] = to_color(val) + + def pane_title_bar_inactive_fg(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['pane_title_bar_inactive_fg'] = to_color(val) + + def pane_title_template(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['pane_title_template'] = tab_title_template(val) + def paste_actions(self, val: str, ans: dict[str, typing.Any]) -> None: ans['paste_actions'] = paste_actions(val) @@ -1322,7 +1356,7 @@ class Parser: raise ValueError(f"The value {val} is not a valid choice for tab_bar_align") ans["tab_bar_align"] = val - choices_for_tab_bar_align = frozenset(('left', 'center', 'right')) + choices_for_tab_bar_align = choices_for_pane_title_bar_align def tab_bar_background(self, val: str, ans: dict[str, typing.Any]) -> None: ans['tab_bar_background'] = to_color_or_none(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index 8272f0c70..a6711a79a 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -25,11 +25,13 @@ choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'text', 'poi choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3'] choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] +choices_for_pane_title_bar = typing.Literal['none', 'top', 'bottom'] +choices_for_pane_title_bar_align = typing.Literal['left', 'center', 'right'] choices_for_placement_strategy = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape choices_for_scrollbar = typing.Literal['scrolled', 'always', 'never', 'hovered', 'scrolled-and-hovered'] choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart'] -choices_for_tab_bar_align = typing.Literal['left', 'center', 'right'] +choices_for_tab_bar_align = choices_for_pane_title_bar_align choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom'] choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted'] choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] @@ -41,6 +43,7 @@ choices_for_window_logo_position = choices_for_placement_strategy option_names = ( 'action_alias', 'active_border_color', + 'active_pane_title_template', 'active_tab_background', 'active_tab_font_style', 'active_tab_foreground', @@ -405,6 +408,13 @@ option_names = ( 'narrow_symbols', 'notify_on_cmd_finish', 'open_url_with', + 'pane_title_bar', + 'pane_title_bar_active_bg', + 'pane_title_bar_active_fg', + 'pane_title_bar_align', + 'pane_title_bar_inactive_bg', + 'pane_title_bar_inactive_fg', + 'pane_title_template', 'paste_actions', 'pixel_scroll', 'placement_strategy', @@ -502,6 +512,7 @@ option_names = ( class Options: active_border_color: kitty.fast_data_types.Color | None = Color(0, 255, 0) + active_pane_title_template: str = 'none' active_tab_background: Color = Color(238, 238, 238) active_tab_font_style: tuple[bool, bool] = (True, True) active_tab_foreground: Color = Color(0, 0, 0) @@ -600,6 +611,13 @@ class Options: mouse_hide_wait: MouseHideWait = MouseHideWait(hide_wait=0.0, show_wait=0.0, show_threshold=40, scroll_show=True) if is_macos else MouseHideWait(hide_wait=3.0, show_wait=0.0, show_threshold=40, scroll_show=True) notify_on_cmd_finish: NotifyOnCmdFinish = NotifyOnCmdFinish(when='never', duration=5.0, action='notify', cmdline=(), clear_on=('focus', 'next')) open_url_with: list[str] = ['default'] + pane_title_bar: choices_for_pane_title_bar = 'none' + pane_title_bar_active_bg: Color = Color(0, 255, 0) + pane_title_bar_active_fg: Color = Color(0, 0, 0) + pane_title_bar_align: choices_for_pane_title_bar_align = 'center' + pane_title_bar_inactive_bg: Color = Color(51, 51, 51) + pane_title_bar_inactive_fg: Color = Color(204, 204, 204) + pane_title_template: str = '{title}' paste_actions: frozenset[str] = frozenset({'confirm', 'quote-urls-at-prompt'}) pixel_scroll: bool = True placement_strategy: choices_for_placement_strategy = 'center' diff --git a/kitty/pane_title_bar.py b/kitty/pane_title_bar.py new file mode 100644 index 000000000..c3953af62 --- /dev/null +++ b/kitty/pane_title_bar.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python +# License: GPL v3 Copyright: 2024, kitty contributors + +from functools import lru_cache +from typing import Any, NamedTuple + +from .fast_data_types import ( + DECAWM, + Screen, + cell_size_for_window, + get_options, + set_pane_title_bar_render_data, +) +from .rgb import color_as_sgr, color_from_int, to_color +from .types import WindowGeometry +from .utils import color_as_int, log_error, sgr_sanitizer_pat +from .window_list import WindowList + + +@lru_cache +def _report_template_failure(template: str, e: str) -> None: + log_error(f'Invalid pane title template: "{template}" with error: {e}') + + +@lru_cache +def _compile_template(template: str) -> Any: + try: + return compile('f"""' + template + '"""', '', 'eval') + except Exception as e: + _report_template_failure(template, str(e)) + + +safe_builtins = { + 'max': max, 'min': min, 'str': str, 'repr': repr, 'abs': abs, + 'len': len, 'chr': chr, 'ord': ord, +} + + +class PaneTitleColorFormatter: + is_active: bool = False + + def __init__(self, which: str): + self.which = which + + def __getattr__(self, name: str) -> str: + q = name + if q == 'default': + ans = '9' + elif q == 'pane': + opts = get_options() + if self.is_active: + col = color_from_int(color_as_int(opts.pane_title_bar_active_fg if self.which == '3' else opts.pane_title_bar_active_bg)) + else: + col = color_from_int(color_as_int(opts.pane_title_bar_inactive_fg if self.which == '3' else opts.pane_title_bar_inactive_bg)) + ans = f'8{color_as_sgr(col)}' + elif q.startswith('color'): + ans = f'8:5:{int(q[5:])}' + else: + if name.startswith('_'): + q = f'#{name[1:]}' + c = to_color(q) + if c is None: + raise AttributeError(f'{name} is not a valid color') + ans = f'8{color_as_sgr(c)}' + return f'\x1b[{self.which}{ans}m' + + +class PaneTitleFormatter: + reset = '\x1b[0m' + fg = PaneTitleColorFormatter('3') + bg = PaneTitleColorFormatter('4') + bold = '\x1b[1m' + nobold = '\x1b[22m' + italic = '\x1b[3m' + noitalic = '\x1b[23m' + + +def _draw_attributed_string(title: str, screen: Screen) -> None: + if '\x1b' in title: + for x in sgr_sanitizer_pat(for_splitting=True).split(title): + if x.startswith('\x1b') and x.endswith('m'): + screen.apply_sgr(x[2:-1]) + else: + screen.draw(x) + else: + screen.draw(title) + + +class PaneTitleData(NamedTuple): + title: str + is_active: bool + window_id: int + tab_id: int + + +class PaneTitleBarScreen: + def __init__(self, os_window_id: int, cell_width: int, cell_height: int): + self.os_window_id = os_window_id + self.cell_width = cell_width + self.screen = Screen(None, 1, 10, 0, cell_width, cell_height) + self.screen.reset_mode(DECAWM) + + def layout(self, geometry: WindowGeometry) -> None: + ncells = max(4, (geometry.right - geometry.left) // self.cell_width) + self.screen.resize(1, ncells) + self.geometry = geometry + + def render(self, data: PaneTitleData) -> None: + opts = get_options() + s = self.screen + s.cursor.x = 0 + s.erase_in_line(2, False) + + is_active = data.is_active + if is_active: + s.color_profile.default_fg = opts.pane_title_bar_active_fg + s.color_profile.default_bg = opts.pane_title_bar_active_bg + fg = (color_as_int(opts.pane_title_bar_active_fg) << 8) | 2 + bg = (color_as_int(opts.pane_title_bar_active_bg) << 8) | 2 + else: + s.color_profile.default_fg = opts.pane_title_bar_inactive_fg + s.color_profile.default_bg = opts.pane_title_bar_inactive_bg + fg = (color_as_int(opts.pane_title_bar_inactive_fg) << 8) | 2 + bg = (color_as_int(opts.pane_title_bar_inactive_bg) << 8) | 2 + + s.cursor.fg = fg + s.cursor.bg = bg + + template = opts.pane_title_template + if is_active and opts.active_pane_title_template and opts.active_pane_title_template != 'none': + template = opts.active_pane_title_template + + PaneTitleColorFormatter.is_active = is_active + eval_locals = { + 'title': data.title, + 'is_active': is_active, + 'fmt': PaneTitleFormatter, + } + try: + title = eval(_compile_template(template), {'__builtins__': safe_builtins}, eval_locals) + except Exception as e: + _report_template_failure(template, str(e)) + title = data.title + + title_str = str(title) + align = opts.pane_title_bar_align + + if align == 'left': + _draw_attributed_string(title_str, s) + else: + # Measure the title length by drawing to cursor position 0 + # and checking where the cursor ends up + _draw_attributed_string(title_str, s) + title_len = s.cursor.x + s.cursor.x = 0 + s.erase_in_line(2, False) + s.cursor.fg = fg + s.cursor.bg = bg + + if align == 'center': + pad = max(0, (s.columns - title_len) // 2) + else: # right + pad = max(0, s.columns - title_len) + + for _ in range(pad): + s.draw(' ') + _draw_attributed_string(title_str, s) + + # Fill remaining cells with background + while s.cursor.x < s.columns: + s.draw(' ') + + +class PaneTitleBarManager: + + def __init__(self, os_window_id: int, tab_id: int): + self.os_window_id = os_window_id + self.tab_id = tab_id + self._screens: dict[int, PaneTitleBarScreen] = {} + + def _clear_all(self) -> None: + for wid, pts in self._screens.items(): + # Zero geometry so the C render loop skips drawing + set_pane_title_bar_render_data( + self.os_window_id, self.tab_id, wid, pts.screen, + 0, 0, 0, 0, + ) + self._screens.clear() + + def update(self, all_windows: WindowList) -> None: + opts = get_options() + position = opts.pane_title_bar + if position == 'none': + if self._screens: + self._clear_all() + return + + visible_groups = list(all_windows.iter_all_layoutable_groups(only_visible=True)) + if len(visible_groups) < 2: + if self._screens: + self._clear_all() + return + + cell_width, cell_height = cell_size_for_window(self.os_window_id) + active_group = all_windows.active_group + seen_window_ids: set[int] = set() + + for wg in visible_groups: + geom = wg.geometry + if geom is None: + continue + + window = wg.windows[-1] if wg.windows else None + if window is None: + continue + + # Validate geometry has enough space for a title bar + if geom.right <= geom.left or geom.bottom <= geom.top: + continue + if position == 'top' and geom.top < cell_height: + continue + if position == 'bottom' and geom.bottom + cell_height < geom.bottom: # overflow check + continue + + wid = window.id + seen_window_ids.add(wid) + + if wid not in self._screens: + self._screens[wid] = PaneTitleBarScreen(self.os_window_id, cell_width, cell_height) + + pts = self._screens[wid] + + # Calculate title bar geometry + if position == 'top': + title_geom = WindowGeometry( + left=geom.left, + top=geom.top - cell_height, + right=geom.right, + bottom=geom.top, + xnum=0, ynum=1, + ) + else: + title_geom = WindowGeometry( + left=geom.left, + top=geom.bottom, + right=geom.right, + bottom=geom.bottom + cell_height, + xnum=0, ynum=1, + ) + + pts.layout(title_geom) + + is_active = wg is active_group + data = PaneTitleData( + title=window.title or '', + is_active=is_active, + window_id=wid, + tab_id=self.tab_id, + ) + pts.render(data) + + set_pane_title_bar_render_data( + self.os_window_id, self.tab_id, wid, pts.screen, + title_geom.left, title_geom.top, title_geom.right, title_geom.bottom, + ) + + # Clean up screens for windows that are no longer visible + stale = set(self._screens) - seen_window_ids + for wid in stale: + del self._screens[wid] + + def destroy(self) -> None: + self._screens.clear() diff --git a/kitty/state.c b/kitty/state.c index e0e5fc0cb..e37512e4c 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -255,12 +255,16 @@ add_tab(id_type os_window_id) { static void create_gpu_resources_for_window(Window *w) { w->render_data.vao_idx = create_cell_vao(); + w->pane_title_render_data.vao_idx = create_cell_vao(); } static void release_gpu_resources_for_window(Window *w) { if (w->render_data.vao_idx > -1) remove_vao(w->render_data.vao_idx); w->render_data.vao_idx = -1; + if (w->pane_title_render_data.vao_idx > -1) remove_vao(w->pane_title_render_data.vao_idx); + w->pane_title_render_data.vao_idx = -1; + Py_CLEAR(w->pane_title_render_data.screen); } static bool @@ -855,6 +859,17 @@ PYWRAP1(set_tab_bar_render_data) { Py_RETURN_NONE; } +PYWRAP1(set_pane_title_bar_render_data) { + WindowGeometry g; + id_type os_window_id, tab_id, window_id; + Screen *screen; + PA("KKKOIIII", &os_window_id, &tab_id, &window_id, &screen, &g.left, &g.top, &g.right, &g.bottom); + WITH_WINDOW(os_window_id, tab_id, window_id) + init_window_render_data(&window->pane_title_render_data, g, screen); + END_WITH_WINDOW + Py_RETURN_NONE; +} + static PyTypeObject RegionType; static PyStructSequence_Field region_fields[] = { {"left", ""}, {"top", ""}, {"right", ""}, {"bottom", ""}, {"width", ""}, {"height", ""}, {NULL, NULL} @@ -1592,6 +1607,7 @@ static PyMethodDef module_methods[] = { MW(reorder_tabs, METH_VARARGS), MW(set_borders_rects, METH_VARARGS), MW(set_tab_bar_render_data, METH_VARARGS), + MW(set_pane_title_bar_render_data, METH_VARARGS), MW(set_window_render_data, METH_VARARGS), MW(set_window_padding, METH_VARARGS), MW(viewport_for_window, METH_VARARGS), diff --git a/kitty/state.h b/kitty/state.h index 38c8a3cc9..05aec3b44 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -208,6 +208,7 @@ typedef struct Window { bool visible; PyObject *title; WindowRenderData render_data; + WindowRenderData pane_title_render_data; WindowLogoRenderData window_logo; MousePosition mouse_pos; struct { diff --git a/kitty/tabs.py b/kitty/tabs.py index 7ba37c54a..217f73cd2 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -15,6 +15,7 @@ from gettext import gettext as _ from typing import Any, Concatenate, Deque, NamedTuple, Optional, ParamSpec, TypeVar, cast from .borders import Border, Borders +from .pane_title_bar import PaneTitleBarManager from .child import Child from .cli_stub import CLIOptions, SaveAsSessionOptions from .constants import appname @@ -170,6 +171,7 @@ class Tab: # {{{ self.name = getattr(session_tab, 'name', '') self.enabled_layouts = [x.lower() for x in getattr(session_tab, 'enabled_layouts', None) or get_options().enabled_layouts] self.borders = Borders(self.os_window_id, self.id) + self.pane_title_bar_manager = PaneTitleBarManager(self.os_window_id, self.id) self.windows: WindowList = WindowList(self) self._last_used_layout: str | None = None self._current_layout_name: str | None = None @@ -440,6 +442,7 @@ class Tab: # {{{ self.mark_tab_bar_dirty() def title_changed(self, window: Window) -> None: + self.pane_title_bar_manager.update(self.windows) if window is self.active_window: tm = self.tab_manager_ref() if tm is not None: @@ -468,6 +471,7 @@ class Tab: # {{{ current_layout=ly, tab_bar_rects=tm.tab_bar_rects, draw_window_borders=draw_borders ) + self.pane_title_bar_manager.update(self.windows) def create_layout_object(self, name: str) -> Layout: return create_layout_object_for(name, self.os_window_id, self.id) diff --git a/tools/themes/collection.go b/tools/themes/collection.go index 6191c92e6..5ba3fb4d1 100644 --- a/tools/themes/collection.go +++ b/tools/themes/collection.go @@ -35,290 +35,294 @@ var _ = fmt.Print var AllColorSettingNames = map[string]bool{ // {{{ // generated by gen-config.py do not edit // ALL_COLORS_START - "active_border_color": true, - "active_tab_background": true, - "active_tab_foreground": true, - "background": true, - "bell_border_color": true, - "color0": true, - "color1": true, - "color10": true, - "color100": true, - "color101": true, - "color102": true, - "color103": true, - "color104": true, - "color105": true, - "color106": true, - "color107": true, - "color108": true, - "color109": true, - "color11": true, - "color110": true, - "color111": true, - "color112": true, - "color113": true, - "color114": true, - "color115": true, - "color116": true, - "color117": true, - "color118": true, - "color119": true, - "color12": true, - "color120": true, - "color121": true, - "color122": true, - "color123": true, - "color124": true, - "color125": true, - "color126": true, - "color127": true, - "color128": true, - "color129": true, - "color13": true, - "color130": true, - "color131": true, - "color132": true, - "color133": true, - "color134": true, - "color135": true, - "color136": true, - "color137": true, - "color138": true, - "color139": true, - "color14": true, - "color140": true, - "color141": true, - "color142": true, - "color143": true, - "color144": true, - "color145": true, - "color146": true, - "color147": true, - "color148": true, - "color149": true, - "color15": true, - "color150": true, - "color151": true, - "color152": true, - "color153": true, - "color154": true, - "color155": true, - "color156": true, - "color157": true, - "color158": true, - "color159": true, - "color16": true, - "color160": true, - "color161": true, - "color162": true, - "color163": true, - "color164": true, - "color165": true, - "color166": true, - "color167": true, - "color168": true, - "color169": true, - "color17": true, - "color170": true, - "color171": true, - "color172": true, - "color173": true, - "color174": true, - "color175": true, - "color176": true, - "color177": true, - "color178": true, - "color179": true, - "color18": true, - "color180": true, - "color181": true, - "color182": true, - "color183": true, - "color184": true, - "color185": true, - "color186": true, - "color187": true, - "color188": true, - "color189": true, - "color19": true, - "color190": true, - "color191": true, - "color192": true, - "color193": true, - "color194": true, - "color195": true, - "color196": true, - "color197": true, - "color198": true, - "color199": true, - "color2": true, - "color20": true, - "color200": true, - "color201": true, - "color202": true, - "color203": true, - "color204": true, - "color205": true, - "color206": true, - "color207": true, - "color208": true, - "color209": true, - "color21": true, - "color210": true, - "color211": true, - "color212": true, - "color213": true, - "color214": true, - "color215": true, - "color216": true, - "color217": true, - "color218": true, - "color219": true, - "color22": true, - "color220": true, - "color221": true, - "color222": true, - "color223": true, - "color224": true, - "color225": true, - "color226": true, - "color227": true, - "color228": true, - "color229": true, - "color23": true, - "color230": true, - "color231": true, - "color232": true, - "color233": true, - "color234": true, - "color235": true, - "color236": true, - "color237": true, - "color238": true, - "color239": true, - "color24": true, - "color240": true, - "color241": true, - "color242": true, - "color243": true, - "color244": true, - "color245": true, - "color246": true, - "color247": true, - "color248": true, - "color249": true, - "color25": true, - "color250": true, - "color251": true, - "color252": true, - "color253": true, - "color254": true, - "color255": true, - "color26": true, - "color27": true, - "color28": true, - "color29": true, - "color3": true, - "color30": true, - "color31": true, - "color32": true, - "color33": true, - "color34": true, - "color35": true, - "color36": true, - "color37": true, - "color38": true, - "color39": true, - "color4": true, - "color40": true, - "color41": true, - "color42": true, - "color43": true, - "color44": true, - "color45": true, - "color46": true, - "color47": true, - "color48": true, - "color49": true, - "color5": true, - "color50": true, - "color51": true, - "color52": true, - "color53": true, - "color54": true, - "color55": true, - "color56": true, - "color57": true, - "color58": true, - "color59": true, - "color6": true, - "color60": true, - "color61": true, - "color62": true, - "color63": true, - "color64": true, - "color65": true, - "color66": true, - "color67": true, - "color68": true, - "color69": true, - "color7": true, - "color70": true, - "color71": true, - "color72": true, - "color73": true, - "color74": true, - "color75": true, - "color76": true, - "color77": true, - "color78": true, - "color79": true, - "color8": true, - "color80": true, - "color81": true, - "color82": true, - "color83": true, - "color84": true, - "color85": true, - "color86": true, - "color87": true, - "color88": true, - "color89": true, - "color9": true, - "color90": true, - "color91": true, - "color92": true, - "color93": true, - "color94": true, - "color95": true, - "color96": true, - "color97": true, - "color98": true, - "color99": true, - "cursor": true, - "cursor_text_color": true, - "cursor_trail_color": true, - "foreground": true, - "inactive_border_color": true, - "inactive_tab_background": true, - "inactive_tab_foreground": true, - "macos_titlebar_color": true, - "mark1_background": true, - "mark1_foreground": true, - "mark2_background": true, - "mark2_foreground": true, - "mark3_background": true, - "mark3_foreground": true, - "scrollbar_handle_color": true, - "scrollbar_track_color": true, - "selection_background": true, - "selection_foreground": true, - "tab_bar_background": true, - "tab_bar_margin_color": true, - "url_color": true, - "visual_bell_color": true, - "wayland_titlebar_color": true, // ALL_COLORS_END + "active_border_color": true, + "active_tab_background": true, + "active_tab_foreground": true, + "background": true, + "bell_border_color": true, + "color0": true, + "color1": true, + "color10": true, + "color100": true, + "color101": true, + "color102": true, + "color103": true, + "color104": true, + "color105": true, + "color106": true, + "color107": true, + "color108": true, + "color109": true, + "color11": true, + "color110": true, + "color111": true, + "color112": true, + "color113": true, + "color114": true, + "color115": true, + "color116": true, + "color117": true, + "color118": true, + "color119": true, + "color12": true, + "color120": true, + "color121": true, + "color122": true, + "color123": true, + "color124": true, + "color125": true, + "color126": true, + "color127": true, + "color128": true, + "color129": true, + "color13": true, + "color130": true, + "color131": true, + "color132": true, + "color133": true, + "color134": true, + "color135": true, + "color136": true, + "color137": true, + "color138": true, + "color139": true, + "color14": true, + "color140": true, + "color141": true, + "color142": true, + "color143": true, + "color144": true, + "color145": true, + "color146": true, + "color147": true, + "color148": true, + "color149": true, + "color15": true, + "color150": true, + "color151": true, + "color152": true, + "color153": true, + "color154": true, + "color155": true, + "color156": true, + "color157": true, + "color158": true, + "color159": true, + "color16": true, + "color160": true, + "color161": true, + "color162": true, + "color163": true, + "color164": true, + "color165": true, + "color166": true, + "color167": true, + "color168": true, + "color169": true, + "color17": true, + "color170": true, + "color171": true, + "color172": true, + "color173": true, + "color174": true, + "color175": true, + "color176": true, + "color177": true, + "color178": true, + "color179": true, + "color18": true, + "color180": true, + "color181": true, + "color182": true, + "color183": true, + "color184": true, + "color185": true, + "color186": true, + "color187": true, + "color188": true, + "color189": true, + "color19": true, + "color190": true, + "color191": true, + "color192": true, + "color193": true, + "color194": true, + "color195": true, + "color196": true, + "color197": true, + "color198": true, + "color199": true, + "color2": true, + "color20": true, + "color200": true, + "color201": true, + "color202": true, + "color203": true, + "color204": true, + "color205": true, + "color206": true, + "color207": true, + "color208": true, + "color209": true, + "color21": true, + "color210": true, + "color211": true, + "color212": true, + "color213": true, + "color214": true, + "color215": true, + "color216": true, + "color217": true, + "color218": true, + "color219": true, + "color22": true, + "color220": true, + "color221": true, + "color222": true, + "color223": true, + "color224": true, + "color225": true, + "color226": true, + "color227": true, + "color228": true, + "color229": true, + "color23": true, + "color230": true, + "color231": true, + "color232": true, + "color233": true, + "color234": true, + "color235": true, + "color236": true, + "color237": true, + "color238": true, + "color239": true, + "color24": true, + "color240": true, + "color241": true, + "color242": true, + "color243": true, + "color244": true, + "color245": true, + "color246": true, + "color247": true, + "color248": true, + "color249": true, + "color25": true, + "color250": true, + "color251": true, + "color252": true, + "color253": true, + "color254": true, + "color255": true, + "color26": true, + "color27": true, + "color28": true, + "color29": true, + "color3": true, + "color30": true, + "color31": true, + "color32": true, + "color33": true, + "color34": true, + "color35": true, + "color36": true, + "color37": true, + "color38": true, + "color39": true, + "color4": true, + "color40": true, + "color41": true, + "color42": true, + "color43": true, + "color44": true, + "color45": true, + "color46": true, + "color47": true, + "color48": true, + "color49": true, + "color5": true, + "color50": true, + "color51": true, + "color52": true, + "color53": true, + "color54": true, + "color55": true, + "color56": true, + "color57": true, + "color58": true, + "color59": true, + "color6": true, + "color60": true, + "color61": true, + "color62": true, + "color63": true, + "color64": true, + "color65": true, + "color66": true, + "color67": true, + "color68": true, + "color69": true, + "color7": true, + "color70": true, + "color71": true, + "color72": true, + "color73": true, + "color74": true, + "color75": true, + "color76": true, + "color77": true, + "color78": true, + "color79": true, + "color8": true, + "color80": true, + "color81": true, + "color82": true, + "color83": true, + "color84": true, + "color85": true, + "color86": true, + "color87": true, + "color88": true, + "color89": true, + "color9": true, + "color90": true, + "color91": true, + "color92": true, + "color93": true, + "color94": true, + "color95": true, + "color96": true, + "color97": true, + "color98": true, + "color99": true, + "cursor": true, + "cursor_text_color": true, + "cursor_trail_color": true, + "foreground": true, + "inactive_border_color": true, + "inactive_tab_background": true, + "inactive_tab_foreground": true, + "macos_titlebar_color": true, + "mark1_background": true, + "mark1_foreground": true, + "mark2_background": true, + "mark2_foreground": true, + "mark3_background": true, + "mark3_foreground": true, + "pane_title_bar_active_bg": true, + "pane_title_bar_active_fg": true, + "pane_title_bar_inactive_bg": true, + "pane_title_bar_inactive_fg": true, + "scrollbar_handle_color": true, + "scrollbar_track_color": true, + "selection_background": true, + "selection_foreground": true, + "tab_bar_background": true, + "tab_bar_margin_color": true, + "url_color": true, + "visual_bell_color": true, + "wayland_titlebar_color": true, // ALL_COLORS_END } // }}} type JSONMetadata struct {