diff --git a/kitty/rc/goto_layout.py b/kitty/rc/goto_layout.py index e184e3dac..63a2ea355 100644 --- a/kitty/rc/goto_layout.py +++ b/kitty/rc/goto_layout.py @@ -25,12 +25,14 @@ class GotoLayout(RemoteCommand): desc = ( 'Set the window layout in the specified tabs (or the active tab if not specified).' ' You can use special match value :code:`all` to set the layout in all tabs.' + ' In case there are multiple layouts with the same name but different options,' + ' specify the full layout definition or a unique prefix of the full definition.' ) options_spec = MATCH_TAB_OPTION args = RemoteCommand.Args( spec='LAYOUT_NAME', count=1, json_field='layout', completion=RemoteCommand.CompletionSpec.from_string('type:keyword group:"Layout" kwds:' + ','.join(layout_names())), - args_choices=layout_names) + ) def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: if len(args) != 1: @@ -44,7 +46,7 @@ class GotoLayout(RemoteCommand): try: tab.goto_layout(payload_get('layout'), raise_exception=True) except ValueError: - raise UnknownLayout('The layout {} is unknown or disabled'.format(payload_get('layout'))) + raise UnknownLayout('The layout {} is unknown or disabled or the name is ambiguous'.format(payload_get('layout'))) return None diff --git a/kitty/tabs.py b/kitty/tabs.py index f2c1c174b..9740c7c48 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -324,20 +324,47 @@ class Tab: # {{{ @ac('lay', ''' Switch to the named layout + In case there are multiple layouts with the same name and different options, + specify the full layout definition or a unique prefix of the full definition. For example:: map f1 goto_layout tall + map f2 goto_layout fat:bias=20 ''') def goto_layout(self, layout_name: str, raise_exception: bool = False) -> None: layout_name = layout_name.lower() - if layout_name not in self.enabled_layouts: - if raise_exception: - raise ValueError(layout_name) - log_error(f'Unknown or disabled layout: {layout_name}') - return - self._set_current_layout(layout_name) - self.relayout() + q, has_colon, rest = layout_name.partition(':') + matches = [] + prefix_matches = [] + matched_layout = '' + for candidate in self.enabled_layouts: + x, _, _ = candidate.partition(':') + if x == q: + if candidate == layout_name: + matched_layout = candidate + break + if candidate.startswith(layout_name): + prefix_matches.append(candidate) + matches.append(x) + + if not matched_layout: + if len(prefix_matches) == 1: + matched_layout = prefix_matches[0] + elif len(matches) == 1: + matched_layout = matches[0] + if matched_layout: + self._set_current_layout(matched_layout) + self.relayout() + else: + if len(matches) == 0: + if raise_exception: + raise ValueError(layout_name) + log_error(f'Unknown or disabled layout: {layout_name}') + elif len(matches) != 1: + if raise_exception: + raise ValueError(layout_name) + log_error(f'Multiple layouts match: {layout_name}') @ac('lay', ''' Toggle the named layout