From 716ff187f9d3ae7e0cc2d6a1cbee4044b1831465 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 17 Oct 2021 18:30:34 +0530 Subject: [PATCH] kitty @ set-enabled-layouts Fixes #4129 --- docs/changelog.rst | 3 ++ kitty/options/utils.py | 10 +++-- kitty/rc/set_enabled_layouts.py | 67 +++++++++++++++++++++++++++++++++ kitty/tabs.py | 15 +++++--- 4 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 kitty/rc/set_enabled_layouts.py diff --git a/docs/changelog.rst b/docs/changelog.rst index ad989fff2..bd20fe588 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -34,6 +34,9 @@ To update |kitty|, :doc:`follow the instructions `. - A new mappable action ``swap_with_window`` to swap the current window with another window in the tab, visually +- A new :program:`remote control command ` to change + the enabled layouts in a tab (:iss:`4129`) + - A new option :opt:`bell_path` to specify the path to a sound file to use as the bell sound diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 885801040..3da32f184 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -518,11 +518,11 @@ def window_size(val: str) -> Tuple[int, str]: return positive_int(val.rstrip('c')), unit -def to_layout_names(raw: str) -> List[str]: +def parse_layout_names(parts: Iterable[str]) -> List[str]: from kitty.layout.interface import all_layouts - parts = [x.strip().lower() for x in raw.split(',')] - ans: List[str] = [] + ans = [] for p in parts: + p = p.lower() if p in ('*', 'all'): ans.extend(sorted(all_layouts)) continue @@ -533,6 +533,10 @@ def to_layout_names(raw: str) -> List[str]: return uniq(ans) +def to_layout_names(raw: str) -> List[str]: + return parse_layout_names((x.strip() for x in raw.split(','))) + + def window_border_width(x: Union[str, int, float]) -> Tuple[float, str]: unit = 'pt' if isinstance(x, str): diff --git a/kitty/rc/set_enabled_layouts.py b/kitty/rc/set_enabled_layouts.py new file mode 100644 index 000000000..477847bb7 --- /dev/null +++ b/kitty/rc/set_enabled_layouts.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2020, Kovid Goyal + +from typing import TYPE_CHECKING, Iterable, Optional + +from kitty.fast_data_types import get_options +from kitty.options.utils import parse_layout_names + +from .base import ( + MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions, + RemoteCommand, ResponseType, Window +) + +if TYPE_CHECKING: + from kitty.cli_stub import SetEnabledLayoutsRCOptions as CLIOptions + + +def layout_names() -> Iterable[str]: + from kitty.layout.interface import all_layouts + return all_layouts.keys() + + +class SetEnabledLayouts(RemoteCommand): + + ''' + layouts+: The list of layout names + match: Which tab to change the layout of + configured: Boolean indicating whether to change the configured value + ''' + + short_desc = 'Set the enabled layouts in a tab' + desc = ( + 'Set the enabled layouts in the specified tab (or the active tab if not specified).' + ' You can use special match value :italic:`all` to set the layout in all tabs. If the' + ' current layout of the tab is not included in the enabled layouts its layout is changed' + ' to the first enabled layout.' + ) + options_spec = MATCH_TAB_OPTION + '''\n\n +--configured +type=bool-set +Change the default enabled layout value so that the new value takes effect for all newly created tabs +as well. +''' + argspec = 'LAYOUTS' + args_completion = {'names': ('Layouts', layout_names)} + + def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: + if len(args) < 1: + self.fatal('At least one layout must be specified') + try: + layouts = parse_layout_names(args) + except ValueError as err: + self.fatal(str(err)) + return {'layouts': layouts, 'match': opts.match} + + def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType: + tabs = self.tabs_for_match_payload(boss, window, payload_get) + layouts = parse_layout_names(payload_get('layouts')) + if payload_get('configured'): + get_options().enabled_layouts = list(layouts) + for tab in tabs: + if tab: + tab.set_enabled_layouts(layouts) + + +set_enabled_layouts = SetEnabledLayouts() diff --git a/kitty/tabs.py b/kitty/tabs.py index e56471a8a..61e54cae2 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -10,8 +10,8 @@ from contextlib import suppress from functools import partial from operator import attrgetter from typing import ( - Any, Deque, Dict, Generator, Iterator, List, NamedTuple, Optional, Pattern, - Sequence, Tuple, Union, cast + Any, Deque, Dict, Generator, Iterable, Iterator, List, NamedTuple, + Optional, Pattern, Sequence, Tuple, Union, cast ) from .borders import Border, Borders @@ -121,14 +121,17 @@ class Tab: # {{{ self._set_current_layout(l0) self.startup(session_tab) - def apply_options(self) -> None: - for window in self: - window.apply_options() - self.enabled_layouts = [x.lower() for x in get_options().enabled_layouts] or ['tall'] + def set_enabled_layouts(self, val: Iterable[str]) -> None: + self.enabled_layouts = [x.lower() for x in val] or ['tall'] if self.current_layout.name not in self.enabled_layouts: self._set_current_layout(self.enabled_layouts[0]) self.relayout() + def apply_options(self) -> None: + for window in self: + window.apply_options() + self.set_enabled_layouts(get_options().enabled_layouts) + def take_over_from(self, other_tab: 'Tab') -> None: self.name, self.cwd = other_tab.name, other_tab.cwd self.enabled_layouts = list(other_tab.enabled_layouts)