Allow changing margings/padding via remote control

Fixes #2546
This commit is contained in:
Kovid Goyal 2020-04-19 19:29:36 +05:30
parent d4a4ee386f
commit 0286940163
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 126 additions and 1 deletions

View File

@ -8,7 +8,8 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
-----------------
- Allow individually setting margins and padding for each edge (left, right,
top, bottom)
top, bottom). Margins can also be controlled per window via remote control
(:iss:`2546`)
- Fix reverse video not being rendered correctly when using transparency or a
background image (:iss:`2419`)

124
kitty/rc/set_spacing.py Normal file
View File

@ -0,0 +1,124 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING, Dict, Optional, List
from .base import (
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window
)
if TYPE_CHECKING:
from kitty.cli_stub import SetSpacingRCOptions as CLIOptions
from kitty.options_stub import Options
def patch_window_edges(w: Window, s: Dict[str, Optional[float]]) -> None:
for k, v in s.items():
which, edge = k.lower().split('-', 1)
if edge == 'left':
w.patch_edge_width(which, 'left', v)
elif edge == 'right':
w.patch_edge_width(which, 'right', v)
elif edge == 'top':
w.patch_edge_width(which, 'top', v)
elif edge == 'bottom':
w.patch_edge_width(which, 'bottom', v)
def patch_configured_edges(opts: 'Options', s: Dict[str, Optional[float]]) -> None:
for k, val in s.items():
if val is None:
continue
which, edge = k.lower().split('-', 1)
q = f'window_{which}_width'
new_edges = getattr(opts, q)._replace(**{edge: val})
setattr(opts, q, new_edges)
class SetSpacing(RemoteCommand):
'''
settings+: An object mapping margins/paddings using canonical form {'margin-top': 50, 'padding-left': null} etc
match_window: Window to change colors in
match_tab: Tab to change colors in
all: Boolean indicating change colors everywhere or not
configured: Boolean indicating whether to change the configured colors. Must be True if reset is True
'''
short_desc = 'Set window padding and margins'
desc = (
'Set the padding and margins for the specified windows (defaults to active window).'
' For example: margin=20 or padding-left=10 or margin-h=30. The shorthand form sets'
' all values, the *-h and *-v variants set horizontal and vertical values.'
' The special value "default" resets to using the default value.'
' If you specify a tab rather than a window, all windows in that tab are affected.'
)
options_spec = '''\
--all -a
type=bool-set
By default, settings are only changed for the currently active window. This option will
cause colors to be changed in all windows.
--configured -c
type=bool-set
Also change the configured padding and margins (i.e. the settings kitty will use for new
windows).
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
argspec = 'MARGIN_OR_PADDING ...'
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
settings: Dict[str, Optional[float]] = {}
mapper: Dict[str, List[str]] = {}
for q in ('margin', 'padding'):
mapper[q] = f'{q}-left {q}-top {q}-right {q}-bottom'.split()
mapper[f'{q}-h'] = mapper[f'{q}-horizontal'] = f'{q}-left {q}-right'.split()
mapper[f'{q}-v'] = mapper[f'{q}-vertical'] = f'{q}-top {q}-bottom'.split()
for edge in ('left', 'top', 'right', 'bottom'):
mapper[f'{q}-{edge}'] = [f'{q}-{edge}']
if not args:
self.fatal('At least one setting must be specified')
for spec in args:
parts = spec.split('=', 1)
if len(parts) != 2:
self.fatal(f'{spec} is not a valid setting')
which = mapper.get(parts[0].lower())
if not which:
self.fatal(f'{parts[0]} is not a valid edge specification')
if parts[1].lower() == 'default':
val = None
else:
try:
val = float(parts[1])
except Exception:
self.fatal(f'{parts[1]} is not a number')
for q in which:
settings[q] = val
ans = {
'match_window': opts.match, 'match_tab': opts.match_tab,
'all': opts.all, 'configured': opts.configured,
'settings': settings
}
return ans
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
windows = self.windows_for_payload(boss, window, payload_get)
settings: Dict[str, Optional[float]] = payload_get('settings')
dirtied_tabs = {}
if payload_get('configured'):
patch_configured_edges(boss.opts, settings)
for w in windows:
patch_window_edges(w, settings)
tab = w.tabref()
if tab is not None:
dirtied_tabs[tab.id] = tab
for tab in dirtied_tabs.values():
tab.relayout()
set_spacing = SetSpacing()