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.
This commit is contained in:
alex-huff
2025-09-21 23:41:48 -05:00
parent b401e12fd9
commit 0daab6ab43
4 changed files with 40 additions and 17 deletions

View File

@@ -5,7 +5,7 @@ import os
import sys import sys
from contextlib import suppress from contextlib import suppress
from functools import partial 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 import parse_args
from kitty.cli_stub import PanelCLIOptions from kitty.cli_stub import PanelCLIOptions
@@ -46,7 +46,7 @@ def panel_kitten_options_spec() -> str:
return ans 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( return parse_args(
args, panel_kitten_options_spec, usage, help_text, 'kitty +kitten panel', args, panel_kitten_options_spec, usage, help_text, 'kitty +kitten panel',
result_class=PanelCLIOptions, track_seen_options=track_seen_options) result_class=PanelCLIOptions, track_seen_options=track_seen_options)

View File

@@ -593,7 +593,7 @@ PreparsedCLIFlags = tuple[dict[str, tuple[Any, bool]], list[str]]
def apply_preparsed_cli_flags( def apply_preparsed_cli_flags(
preparsed_from_c: PreparsedCLIFlags, ans: Any, create_oc: Callable[[], Options], 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]: ) -> list[str]:
for key, (val, is_seen) in preparsed_from_c[0].items(): for key, (val, is_seen) in preparsed_from_c[0].items():
if key == 'help' and is_seen and val: 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: elif key == 'version' and is_seen and val:
create_oc().handle_version() create_oc().handle_version()
if is_seen and track_seen_options is not None: if is_seen and track_seen_options is not None:
track_seen_options.add(key) track_seen_options[key] = val
setattr(ans, key, val) setattr(ans, key, val)
return preparsed_from_c[1] return preparsed_from_c[1]
def parse_cmdline_inner( def parse_cmdline_inner(
args: list[str], oc: Options, disabled: OptionSpecSeq, names_map: dict[str, OptionDict], 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]: ) -> list[str]:
preparsed = parse_cli_from_spec(args, names_map, values_map) preparsed = parse_cli_from_spec(args, names_map, values_map)
leftover_args = apply_preparsed_cli_flags(preparsed, ans, lambda: oc, track_seen_options) leftover_args = apply_preparsed_cli_flags(preparsed, ans, lambda: oc, track_seen_options)
@@ -620,7 +620,7 @@ def parse_cmdline_inner(
def parse_cmdline( def parse_cmdline(
oc: Options, disabled: OptionSpecSeq, ans: Any, args: list[str] | None = None, 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]: ) -> list[str]:
names_map = oc.names_map.copy() names_map = oc.names_map.copy()
values_map = oc.values_map.copy() values_map = oc.values_map.copy()
@@ -677,7 +677,7 @@ def parse_args(
appname: str | None = None, appname: str | None = None,
result_class: type[T] | None = None, result_class: type[T] | None = None,
preparsed_from_c: PreparsedCLIFlags | 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]]: ) -> tuple[T, list[str]]:
if result_class is not None: if result_class is not None:
ans = result_class() ans = result_class()

View File

@@ -443,7 +443,7 @@ def get_env(opts: LaunchCLIOptions, active_child: Child | None = None, base_env:
return 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 from kittens.panel.main import layer_shell_config, parse_panel_args
args = [('' if x.startswith('--') else '--') + x for x in panel_opts] args = [('' if x.startswith('--') else '--') + x for x in panel_opts]
try: try:

View File

@@ -1,7 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
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 ( from .base import (
MATCH_WINDOW_OPTION, MATCH_WINDOW_OPTION,
@@ -73,7 +79,7 @@ type=bool-set
Treat the specified sizes as increments on the existing window size Treat the specified sizes as increments on the existing window size
instead of absolute sizes. When using :option:`--action`=:code:`os-panel`, instead of absolute sizes. When using :option:`--action`=:code:`os-panel`,
only the specified settings are changed, otherwise non-specified settings only the specified settings are changed, otherwise non-specified settings
are reset to default. keep their current value.
--self --self
@@ -119,23 +125,40 @@ using this option means that you will not be notified of failures.
if not panels: if not panels:
raise RemoteControlErrorWithoutTraceback('Must specify at least one panel setting') raise RemoteControlErrorWithoutTraceback('Must specify at least one panel setting')
from kitty.launch import layer_shell_config_from_panel_opts from kitty.launch import layer_shell_config_from_panel_opts
seen_options: set[str] = set() seen_options: dict[str, Any] = {}
try: try:
lsc = layer_shell_config_from_panel_opts(panels, track_seen_options=seen_options) lsc = layer_shell_config_from_panel_opts(panels, track_seen_options=seen_options)
except Exception as e: except Exception as e:
raise RemoteControlErrorWithoutTraceback( raise RemoteControlErrorWithoutTraceback(
f'Invalid panel options specified: {e}') f'Invalid panel options specified: {e}')
if payload_get('incremental'): 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) existing = layer_shell_config_for_os_window(os_window_id)
if existing is None: if existing is None:
raise RemoteControlErrorWithoutTraceback( raise RemoteControlErrorWithoutTraceback(
f'The OS Window {os_window_id} has no panel configuration') f'The OS Window {os_window_id} has no panel configuration')
defaults = layer_shell_config_from_panel_opts(()) for option in seen_options.keys():
replacements = {} for config in cli_option_to_lsc_configs_map[option]:
for x in lsc._fields: existing[config] = getattr(lsc, config)
if x not in seen_options: if seen_options.get('edge', None) == 'background':
replacements[x] = getattr(defaults, x) existing['type'] = GLFW_LAYER_SHELL_BACKGROUND
lsc = lsc._replace(**replacements) 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): if not set_layer_shell_config(os_window_id, lsc):
raise RemoteControlErrorWithoutTraceback(f'Failed to change panel configuration for OS Window {os_window_id}') raise RemoteControlErrorWithoutTraceback(f'Failed to change panel configuration for OS Window {os_window_id}')
elif ac == 'toggle-visibility': elif ac == 'toggle-visibility':