@@ -7,6 +7,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
|||||||
0.19.3 [future]
|
0.19.3 [future]
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
- A new :doc:`broadcast <kittens/broadcast>` kitten to type in all kitty windows
|
||||||
|
simultaneously (:iss:`1569`)
|
||||||
|
|
||||||
- Add a new mappable `select_tab` action to choose a tab to switch to even
|
- Add a new mappable `select_tab` action to choose a tab to switch to even
|
||||||
when the tab bar is hidden (:iss:`3115`)
|
when the tab bar is hidden (:iss:`3115`)
|
||||||
|
|
||||||
|
|||||||
23
docs/kittens/broadcast.rst
Normal file
23
docs/kittens/broadcast.rst
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
broadcast - type text in all kitty windows
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
The ``broadcast`` kitten can be used to type text simultaneously in
|
||||||
|
all kitty windows (or a subset as desired).
|
||||||
|
|
||||||
|
To use it, simply create a mapping in :file:`kitty.conf` such as::
|
||||||
|
|
||||||
|
map F1 launch --allow-remote-control kitty +kitten broadcast
|
||||||
|
|
||||||
|
Then press the :kbd:`F1` key and whatever you type in the newly created widow
|
||||||
|
will be sent to all kitty windows.
|
||||||
|
|
||||||
|
You can use the options described below to control which windows
|
||||||
|
are selected.
|
||||||
|
|
||||||
|
.. program:: kitty +kitten broadcast
|
||||||
|
|
||||||
|
|
||||||
|
Command Line Interface
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. include:: /generated/cli-kitten-broadcast.rst
|
||||||
@@ -148,6 +148,19 @@ as the syntax for what follows :code:`kitty @` above. You do not need
|
|||||||
to enable remote control to use these mappings.
|
to enable remote control to use these mappings.
|
||||||
|
|
||||||
|
|
||||||
|
Broadcasting what you type to all kitty windows
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
As a simple illustration of the power of remote control, lets
|
||||||
|
have what we type sent to all open kitty windows. To do that define the
|
||||||
|
following mapping in :file:`kitty.conf`::
|
||||||
|
|
||||||
|
map F1 launch --allow-remote-control kitty +kitten broadcast
|
||||||
|
|
||||||
|
Now press, F1 and start typing, what you type will be sent to all windows,
|
||||||
|
live, as you type it.
|
||||||
|
|
||||||
|
|
||||||
Documentation for the remote control protocol
|
Documentation for the remote control protocol
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
0
kittens/broadcast/__init__.py
Normal file
0
kittens/broadcast/__init__.py
Normal file
99
kittens/broadcast/main.py
Normal file
99
kittens/broadcast/main.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from base64 import standard_b64encode
|
||||||
|
from gettext import gettext as _
|
||||||
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
from kitty.cli import parse_args
|
||||||
|
from kitty.cli_stub import BroadcastCLIOptions
|
||||||
|
from kitty.key_encoding import RELEASE, key_defs as K
|
||||||
|
from kitty.rc.base import MATCH_TAB_OPTION, MATCH_WINDOW_OPTION
|
||||||
|
from kitty.remote_control import create_basic_command, encode_send
|
||||||
|
from kitty.typing import KeyEventType
|
||||||
|
|
||||||
|
from ..tui.handler import Handler
|
||||||
|
from ..tui.loop import Loop
|
||||||
|
from ..tui.operations import styled
|
||||||
|
|
||||||
|
|
||||||
|
class Broadcast(Handler):
|
||||||
|
|
||||||
|
def __init__(self, opts: BroadcastCLIOptions, initial_strings: List[str]) -> None:
|
||||||
|
self.opts = opts
|
||||||
|
self.initial_strings = initial_strings
|
||||||
|
self.payload = {'exclude_active': True, 'data': '', 'match': opts.match_tab, 'match_tab': opts.match_tab}
|
||||||
|
if not opts.match and not opts.match_tab:
|
||||||
|
self.payload['all'] = True
|
||||||
|
|
||||||
|
def initialize(self) -> None:
|
||||||
|
self.print('Type the text to broadcast below, press', styled('Ctrl+c', fg='yellow'), 'to quit:')
|
||||||
|
for x in self.initial_strings:
|
||||||
|
self.write_broadcast_text(x)
|
||||||
|
|
||||||
|
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||||
|
self.write_broadcast_text(text)
|
||||||
|
self.write(text)
|
||||||
|
|
||||||
|
def on_interrupt(self) -> None:
|
||||||
|
self.quit_loop(0)
|
||||||
|
|
||||||
|
def on_eot(self) -> None:
|
||||||
|
self.write_broadcast_text('\x04')
|
||||||
|
|
||||||
|
def on_key(self, key_event: KeyEventType) -> None:
|
||||||
|
if key_event.type is not RELEASE and not key_event.mods:
|
||||||
|
if key_event.key is K['TAB']:
|
||||||
|
self.write_broadcast_text('\t')
|
||||||
|
self.write('\t')
|
||||||
|
elif key_event.key is K['BACKSPACE']:
|
||||||
|
self.write_broadcast_text('\177')
|
||||||
|
self.write('\x08\x1b[X')
|
||||||
|
elif key_event.key is K['ENTER']:
|
||||||
|
self.write_broadcast_text('\r')
|
||||||
|
self.print('')
|
||||||
|
|
||||||
|
def write_broadcast_text(self, text: str) -> None:
|
||||||
|
self.write_broadcast_data('base64:' + standard_b64encode(text.encode('utf-8')).decode('ascii'))
|
||||||
|
|
||||||
|
def write_broadcast_data(self, data: str) -> None:
|
||||||
|
payload = self.payload.copy()
|
||||||
|
payload['data'] = data
|
||||||
|
send = create_basic_command('send-text', payload, no_response=True)
|
||||||
|
self.write(encode_send(send))
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONS = (MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format
|
||||||
|
help_text = 'Broadcast typed text to all kitty windows. By default text is sent to all windows, unless one of the matching options is specified'
|
||||||
|
usage = '[initial text to send ...]'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_broadcast_args(args: List[str]) -> Tuple[BroadcastCLIOptions, List[str]]:
|
||||||
|
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten broadcast', result_class=BroadcastCLIOptions)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: List[str]) -> Optional[Dict[str, Any]]:
|
||||||
|
try:
|
||||||
|
opts, items = parse_broadcast_args(args[1:])
|
||||||
|
except SystemExit as e:
|
||||||
|
if e.code != 0:
|
||||||
|
print(e.args[0], file=sys.stderr)
|
||||||
|
input(_('Press Enter to quit'))
|
||||||
|
return None
|
||||||
|
|
||||||
|
print('Type text to be broadcast below, Ctrl-C to quit:', end='\r\n')
|
||||||
|
sys.stdout.flush()
|
||||||
|
loop = Loop()
|
||||||
|
handler = Broadcast(opts, items)
|
||||||
|
loop.loop(handler)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
||||||
|
elif __name__ == '__doc__':
|
||||||
|
cd = sys.cli_docs # type: ignore
|
||||||
|
cd['usage'] = usage
|
||||||
|
cd['options'] = OPTIONS
|
||||||
|
cd['help_text'] = help_text
|
||||||
@@ -13,7 +13,7 @@ class CLIOptions:
|
|||||||
LaunchCLIOptions = AskCLIOptions = ClipboardCLIOptions = DiffCLIOptions = CLIOptions
|
LaunchCLIOptions = AskCLIOptions = ClipboardCLIOptions = DiffCLIOptions = CLIOptions
|
||||||
HintsCLIOptions = IcatCLIOptions = PanelCLIOptions = ResizeCLIOptions = CLIOptions
|
HintsCLIOptions = IcatCLIOptions = PanelCLIOptions = ResizeCLIOptions = CLIOptions
|
||||||
ErrorCLIOptions = UnicodeCLIOptions = RCOptions = RemoteFileCLIOptions = CLIOptions
|
ErrorCLIOptions = UnicodeCLIOptions = RCOptions = RemoteFileCLIOptions = CLIOptions
|
||||||
QueryTerminalCLIOptions = CLIOptions
|
QueryTerminalCLIOptions = BroadcastCLIOptions = CLIOptions
|
||||||
|
|
||||||
|
|
||||||
def generate_stub() -> None:
|
def generate_stub() -> None:
|
||||||
@@ -48,6 +48,9 @@ def generate_stub() -> None:
|
|||||||
from kittens.hints.main import OPTIONS
|
from kittens.hints.main import OPTIONS
|
||||||
do(OPTIONS(), 'HintsCLIOptions')
|
do(OPTIONS(), 'HintsCLIOptions')
|
||||||
|
|
||||||
|
from kittens.broadcast.main import OPTIONS
|
||||||
|
do(OPTIONS(), 'BroadcastCLIOptions')
|
||||||
|
|
||||||
from kittens.icat.main import options_spec
|
from kittens.icat.main import options_spec
|
||||||
do(options_spec(), 'IcatCLIOptions')
|
do(options_spec(), 'IcatCLIOptions')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user