Allow sending arbitrary signals to the current foreground process in a window using either a mapping in kitty.conf or via remote control

Fixes #2778
This commit is contained in:
Kovid Goyal
2020-06-20 12:37:27 +05:30
parent 3ff184348e
commit 601a6c9e3d
4 changed files with 76 additions and 0 deletions

View File

@@ -15,6 +15,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- Tall and Fat layouts: Add mappable actions to increase or decrease the number
of full size windows (:iss:`2688`)
- Allow sending arbitrary signals to the current foreground process in a window
using either a mapping in kitty.conf or via remote control (:iss:`2778`)
- Allow sending the back and forward mouse buttons to terminal applications
(:pull:`2742`)

View File

@@ -140,6 +140,20 @@ def float_parse(func: str, rest: str) -> FuncArgsType:
return func, (float(rest),)
@func_with_args('signal_child')
def signal_child_parse(func: str, rest: str) -> FuncArgsType:
import signal
signals = []
for q in rest.split():
try:
signum = getattr(signal, q.upper())
except AttributeError:
log_error(f'Unknown signal: {rest} ignoring')
else:
signals.append(signum)
return func, tuple(signals)
@func_with_args('change_font_size')
def parse_change_font_size(func: str, rest: str) -> Tuple[str, Tuple[bool, Optional[str], float]]:
vals = rest.strip().split(maxsplit=1)

53
kitty/rc/signal_child.py Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import TYPE_CHECKING, Optional
from .base import (
MATCH_WINDOW_OPTION, ArgsType, Boss, MatchError, PayloadGetType,
PayloadType, RCOptions, RemoteCommand, ResponseType, Window
)
if TYPE_CHECKING:
from kitty.cli_stub import SignalChildRCOptions as CLIOptions
class SignalChild(RemoteCommand):
'''
signals: The signals, a list of names, such as SIGTERM, SIGKILL, SIGUSR1, etc.
match: Which windows to change the title in
'''
short_desc = 'Send a signal to the foreground process in the specified window'
desc = (
'Send one or more signals to the foreground process in the specified window(s).'
' If you use the :option:`kitty @ signal-child --match` option'
' the title will be set for all matched windows. By default, only the active'
' window is affected. If you do not specify any signals, :code:`SIGINT` is sent by default.'
' You can also map this to a keystroke in kitty.conf, for example::\n\n'
' map F1 signal_child SIGTERM'
)
options_spec = '''\
''' + '\n\n' + MATCH_WINDOW_OPTION
argspec = '[SIGNAL_NAME ...]'
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'match': opts.match, 'signals': [x.upper() for x in args] or ['SIGINT']}
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
import signal
windows = [window or boss.active_window]
match = payload_get('match')
if match:
windows = list(boss.match_windows(match))
if not windows:
raise MatchError(match)
signals = tuple(getattr(signal, x) for x in payload_get('signals'))
for window in windows:
if window:
window.signal_child(*signals)
signal_child = SignalChild()

View File

@@ -820,4 +820,10 @@ class Window:
def scroll_to_mark(self, prev: bool = True, mark: int = 0) -> None:
self.screen.scroll_to_next_mark(mark, prev)
def signal_child(self, *signals: int) -> None:
pid = self.child.pid_for_cwd
if pid is not None:
for sig in signals:
os.kill(pid, sig)
# }}}