From 0daab6ab4313989bc1210fa6cfee923cd8797252 Mon Sep 17 00:00:00 2001 From: alex-huff Date: Sun, 21 Sep 2025 23:41:48 -0500 Subject: [PATCH] resize-os-window: fix '--incremental' option of 'os-panel' action This commit addresses a few issues with the implementation of '--incremental': - Unspecified settings are reset to their default value, which defeats the purpose of the option. - It is assumed that the names of options in 'LayerCLIOptions' map one to one with the names of fields in 'LayerShellConfig' but this isn't true. For example: The 'margin_top' cli option sets the 'requested_top_margin' layer shell config. - When some options are set to a certain value, they force other options to be some value. The current implementation doesn't account for this. - The documentation is contradictory. --- kittens/panel/main.py | 4 ++-- kitty/cli.py | 10 ++++----- kitty/launch.py | 2 +- kitty/rc/resize_os_window.py | 41 ++++++++++++++++++++++++++++-------- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/kittens/panel/main.py b/kittens/panel/main.py index a82e4e0c1..a1f059796 100644 --- a/kittens/panel/main.py +++ b/kittens/panel/main.py @@ -5,7 +5,7 @@ import os import sys from contextlib import suppress from functools import partial -from typing import Iterable, Mapping, Sequence +from typing import Any, Iterable, Mapping, Sequence from kitty.cli import parse_args from kitty.cli_stub import PanelCLIOptions @@ -46,7 +46,7 @@ def panel_kitten_options_spec() -> str: return ans -def parse_panel_args(args: list[str], track_seen_options: set[str] | None = None) -> tuple[PanelCLIOptions, list[str]]: +def parse_panel_args(args: list[str], track_seen_options: dict[str, Any] | None = None) -> tuple[PanelCLIOptions, list[str]]: return parse_args( args, panel_kitten_options_spec, usage, help_text, 'kitty +kitten panel', result_class=PanelCLIOptions, track_seen_options=track_seen_options) diff --git a/kitty/cli.py b/kitty/cli.py index 614ba0d58..69c4c36b9 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -593,7 +593,7 @@ PreparsedCLIFlags = tuple[dict[str, tuple[Any, bool]], list[str]] def apply_preparsed_cli_flags( preparsed_from_c: PreparsedCLIFlags, ans: Any, create_oc: Callable[[], Options], - track_seen_options: set[str] | None = None + track_seen_options: dict[str, Any] | None = None ) -> list[str]: for key, (val, is_seen) in preparsed_from_c[0].items(): if key == 'help' and is_seen and val: @@ -601,14 +601,14 @@ def apply_preparsed_cli_flags( elif key == 'version' and is_seen and val: create_oc().handle_version() if is_seen and track_seen_options is not None: - track_seen_options.add(key) + track_seen_options[key] = val setattr(ans, key, val) return preparsed_from_c[1] def parse_cmdline_inner( args: list[str], oc: Options, disabled: OptionSpecSeq, names_map: dict[str, OptionDict], - values_map: dict[str, OptionDict], ans: Any, track_seen_options: set[str] | None = None + values_map: dict[str, OptionDict], ans: Any, track_seen_options: dict[str, Any] | None = None ) -> list[str]: preparsed = parse_cli_from_spec(args, names_map, values_map) leftover_args = apply_preparsed_cli_flags(preparsed, ans, lambda: oc, track_seen_options) @@ -620,7 +620,7 @@ def parse_cmdline_inner( def parse_cmdline( oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None, - track_seen_options: set[str] | None = None + track_seen_options: dict[str, Any] | None = None ) -> list[str]: names_map = oc.names_map.copy() values_map = oc.values_map.copy() @@ -677,7 +677,7 @@ def parse_args( appname: str | None = None, result_class: type[T] | None = None, preparsed_from_c: PreparsedCLIFlags | None = None, - track_seen_options: set[str] | None = None, + track_seen_options: dict[str, Any] | None = None, ) -> tuple[T, list[str]]: if result_class is not None: ans = result_class() diff --git a/kitty/launch.py b/kitty/launch.py index 5ae2767a7..7fe321d01 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -443,7 +443,7 @@ def get_env(opts: LaunchCLIOptions, active_child: Child | None = None, base_env: return env -def layer_shell_config_from_panel_opts(panel_opts: Iterable[str], track_seen_options: set[str] | None = None) -> LayerShellConfig: +def layer_shell_config_from_panel_opts(panel_opts: Iterable[str], track_seen_options: dict[str, Any] | None = None) -> LayerShellConfig: from kittens.panel.main import layer_shell_config, parse_panel_args args = [('' if x.startswith('--') else '--') + x for x in panel_opts] try: diff --git a/kitty/rc/resize_os_window.py b/kitty/rc/resize_os_window.py index 2cc4d7208..f5b63aa3d 100644 --- a/kitty/rc/resize_os_window.py +++ b/kitty/rc/resize_os_window.py @@ -1,7 +1,13 @@ #!/usr/bin/env python # License: GPLv3 Copyright: 2020, Kovid Goyal -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any + +from kitty.fast_data_types import ( + GLFW_FOCUS_ON_DEMAND, + GLFW_LAYER_SHELL_BACKGROUND, +) +from kitty.types import LayerShellConfig from .base import ( MATCH_WINDOW_OPTION, @@ -73,7 +79,7 @@ type=bool-set Treat the specified sizes as increments on the existing window size instead of absolute sizes. When using :option:`--action`=:code:`os-panel`, only the specified settings are changed, otherwise non-specified settings -are reset to default. +keep their current value. --self @@ -119,23 +125,40 @@ using this option means that you will not be notified of failures. if not panels: raise RemoteControlErrorWithoutTraceback('Must specify at least one panel setting') from kitty.launch import layer_shell_config_from_panel_opts - seen_options: set[str] = set() + seen_options: dict[str, Any] = {} try: lsc = layer_shell_config_from_panel_opts(panels, track_seen_options=seen_options) except Exception as e: raise RemoteControlErrorWithoutTraceback( f'Invalid panel options specified: {e}') if payload_get('incremental'): + cli_option_to_lsc_configs_map = { + 'lines': ('y_size_in_cells', 'y_size_in_pixels'), + 'columns': ('x_size_in_cells', 'x_size_in_pixels'), + 'margin_top': ('requested_top_margin',), + 'margin_left': ('requested_left_margin',), + 'margin_bottom': ('requested_bottom_margin',), + 'margin_right': ('requested_right_margin',), + 'edge': ('edge',), + 'layer': ('type',), + 'output_name': ('output_name',), + 'focus_policy': ('focus_policy',), + 'exclusive_zone': ('requested_exclusive_zone',), + 'override_exclusive_zone': ('override_exclusive_zone',), + 'hide_on_focus_loss': ('hide_on_focus_loss',) + } existing = layer_shell_config_for_os_window(os_window_id) if existing is None: raise RemoteControlErrorWithoutTraceback( f'The OS Window {os_window_id} has no panel configuration') - defaults = layer_shell_config_from_panel_opts(()) - replacements = {} - for x in lsc._fields: - if x not in seen_options: - replacements[x] = getattr(defaults, x) - lsc = lsc._replace(**replacements) + for option in seen_options.keys(): + for config in cli_option_to_lsc_configs_map[option]: + existing[config] = getattr(lsc, config) + if seen_options.get('edge', None) == 'background': + existing['type'] = GLFW_LAYER_SHELL_BACKGROUND + if existing['hide_on_focus_loss']: + existing['focus_policy'] = GLFW_FOCUS_ON_DEMAND + lsc = LayerShellConfig(**existing) if not set_layer_shell_config(os_window_id, lsc): raise RemoteControlErrorWithoutTraceback(f'Failed to change panel configuration for OS Window {os_window_id}') elif ac == 'toggle-visibility':