diff --git a/kittens/clipboard/__init__.py b/kittens/clipboard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kittens/clipboard/main.py b/kittens/clipboard/main.py new file mode 100644 index 000000000..fcbb38782 --- /dev/null +++ b/kittens/clipboard/main.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2018, Kovid Goyal + +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) diff --git a/kittens/tui/handler.py b/kittens/tui/handler.py index 3c71cf9c1..c552dd38c 100644 --- a/kittens/tui/handler.py +++ b/kittens/tui/handler.py @@ -67,6 +67,9 @@ class Handler: def on_kitty_cmd_response(self, response): pass + def on_clipboard_response(self, text, from_primary=False): + pass + def write(self, data): if isinstance(data, str): data = data.encode('utf-8') diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index b87445fcc..c8661b0ee 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -265,7 +265,15 @@ class Loop: pass 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): if apc.startswith('K'): diff --git a/kittens/tui/operations.py b/kittens/tui/operations.py index 59a20875a..a5784e7a9 100644 --- a/kittens/tui/operations.py +++ b/kittens/tui/operations.py @@ -231,6 +231,17 @@ def set_default_colors(fg=None, bg=None) -> str: 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( (name, obj) for name, obj in globals().items() if hasattr(obj, '__annotations__') and obj.__annotations__.get('return') is str)