Add a kitten to get/set the clipboard via OSC 52

This commit is contained in:
Kovid Goyal 2018-05-21 23:24:27 +05:30
parent 3d37348c2b
commit d3edd2e73f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 103 additions and 1 deletions

View File

80
kittens/clipboard/main.py Normal file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import sys
from kitty.cli import parse_args
from ..tui.handler import Handler
from ..tui.loop import Loop
class Clipboard(Handler):
def __init__(self, data_to_send, args):
self.args = args
self.print_on_fail = None
self.clipboard_contents = None
self.data_to_send = data_to_send
def initialize(self):
if self.data_to_send is not None:
self.cmd.write_to_clipboard(self.data_to_send, self.args.use_primary)
if not self.args.get_clipboard:
self.quit_loop(0)
return
self.cmd.request_from_clipboard(self.args.use_primary)
def on_clipboard_response(self, text, from_primary=False):
self.clipboard_contents = text
self.quit_loop(0)
OPTIONS = r'''
--get-clipboard
default=False
type=bool-set
Output the current contents of the clipboard to stdout. Note that this
will hang if you have not enabled the option to allow reading the clipboard
in kitty.conf
--use-primary
default=False
type=bool-set
Use the primary selection rather than the clipboard on systems that support it,
such as X11.
'''.format
def main(args):
msg = '''\
Read or write to the system clipboard.
To set the clipboard text, pipe in the new text on stdin. Use the --get-clipboard option \
to output the current clipboard contents to stdout. Note that you must enable reading of clipboard in kitty.conf first. '''
args, items = parse_args(args[1:], OPTIONS, '', msg, 'clipboard')
if items:
raise SystemExit('Unrecognized extra command line arguments')
data = None
if not sys.stdin.isatty():
data = sys.stdin.buffer.read()
sys.stdin = open('/dev/tty', 'r')
loop = Loop()
handler = Clipboard(data, args)
loop.loop(handler)
if loop.return_code == 0 and handler.clipboard_contents:
sys.stdout.write(handler.clipboard_contents)
sys.stdout.flush()
if handler.print_on_fail:
print(handler.print_on_fail)
input('Press Enter to quit')
raise SystemExit(loop.return_code)
def handle_result(args, data, target_window_id, boss):
pass
if __name__ == '__main__':
main(sys.argv)

View File

@ -67,6 +67,9 @@ class Handler:
def on_kitty_cmd_response(self, response): def on_kitty_cmd_response(self, response):
pass pass
def on_clipboard_response(self, text, from_primary=False):
pass
def write(self, data): def write(self, data):
if isinstance(data, str): if isinstance(data, str):
data = data.encode('utf-8') data = data.encode('utf-8')

View File

@ -265,7 +265,15 @@ class Loop:
pass pass
def _on_osc(self, osc): def _on_osc(self, osc):
pass m = re.match(r'(\d+);', osc)
if m is not None:
code = int(m.group(1))
rest = osc[m.end():]
if code == 52:
where, rest = rest.partition(';')[::2]
from_primary = 'p' in where
from base64 import standard_b64decode
self.handler.on_clipboard_response(standard_b64decode(rest).decode('utf-8'), from_primary)
def _on_apc(self, apc): def _on_apc(self, apc):
if apc.startswith('K'): if apc.startswith('K'):

View File

@ -231,6 +231,17 @@ def set_default_colors(fg=None, bg=None) -> str:
return ans return ans
def write_to_clipboard(data, use_primary=False) -> str:
if isinstance(data, str):
data = data.encode('utf-8')
from base64 import standard_b64encode
return '\x1b]52;{};{}\x07'.format('p' if use_primary else 'c', standard_b64encode(data).decode('ascii'))
def request_from_clipboard(use_primary=False) -> str:
return '\x1b]52;{};?\x07'.format('p' if use_primary else 'c')
all_cmds = tuple( all_cmds = tuple(
(name, obj) for name, obj in globals().items() (name, obj) for name, obj in globals().items()
if hasattr(obj, '__annotations__') and obj.__annotations__.get('return') is str) if hasattr(obj, '__annotations__') and obj.__annotations__.get('return') is str)