1#!/usr/local/bin/python3.8
2# vim:fileencoding=utf-8
3# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
4
5import os
6import sys
7from typing import List, NoReturn, Optional
8
9from kitty.cli import parse_args
10from kitty.cli_stub import ClipboardCLIOptions
11
12from ..tui.handler import Handler
13from ..tui.loop import Loop
14
15
16class Clipboard(Handler):
17
18    def __init__(self, data_to_send: Optional[bytes], args: ClipboardCLIOptions):
19        self.args = args
20        self.clipboard_contents: Optional[str] = None
21        self.data_to_send = data_to_send
22        self.quit_on_write = False
23
24    def initialize(self) -> None:
25        if self.data_to_send is not None:
26            self.cmd.write_to_clipboard(self.data_to_send, self.args.use_primary)
27        if not self.args.get_clipboard:
28            if self.args.wait_for_completion:
29                # ask kitty for the TN terminfo capability and
30                # only quit after a response is received
31                self.print('\x1bP+q544e\x1b\\', end='')
32                self.print('Waiting for completion...')
33                return
34            self.quit_on_write = True
35            return
36        self.cmd.request_from_clipboard(self.args.use_primary)
37
38    def on_writing_finished(self) -> None:
39        if self.quit_on_write:
40            self.quit_loop(0)
41
42    def on_clipboard_response(self, text: str, from_primary: bool = False) -> None:
43        self.clipboard_contents = text
44        self.quit_loop(0)
45
46    def on_capability_response(self, name: str, val: str) -> None:
47        self.quit_loop(0)
48
49    def on_interrupt(self) -> None:
50        self.quit_loop(1)
51
52    def on_eot(self) -> None:
53        self.quit_loop(1)
54
55
56OPTIONS = r'''
57--get-clipboard
58default=False
59type=bool-set
60Output the current contents of the clipboard to stdout. Note that this
61will not work if you have not enabled the option to allow reading the clipboard
62in kitty.conf
63
64
65--use-primary
66default=False
67type=bool-set
68Use the primary selection rather than the clipboard on systems that support it,
69such as X11.
70
71
72--wait-for-completion
73default=False
74type=bool-set
75Wait till the copy to clipboard is complete before exiting. Useful if running
76the kitten in a dedicated, ephemeral window.
77'''.format
78help_text = '''\
79Read or write to the system clipboard.
80
81To set the clipboard text, pipe in the new text on stdin. Use the
82:option:`--get-clipboard` option to output the current clipboard contents to
83:file:`stdout`. Note that you must enable reading of clipboard in
84:file:`kitty.conf` first.
85'''
86
87usage = ''
88
89
90def main(args: List[str]) -> NoReturn:
91    cli_opts, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard', result_class=ClipboardCLIOptions)
92    if items:
93        raise SystemExit('Unrecognized extra command line arguments')
94    data: Optional[bytes] = None
95    if not sys.stdin.isatty():
96        data = sys.stdin.buffer.read()
97        sys.stdin = open(os.ctermid(), 'r')
98    loop = Loop()
99    handler = Clipboard(data, cli_opts)
100    loop.loop(handler)
101    if loop.return_code == 0 and handler.clipboard_contents:
102        sys.stdout.write(handler.clipboard_contents)
103        sys.stdout.flush()
104    raise SystemExit(loop.return_code)
105
106
107if __name__ == '__main__':
108    main(sys.argv)
109elif __name__ == '__doc__':
110    cd = sys.cli_docs  # type: ignore
111    cd['usage'] = usage
112    cd['options'] = OPTIONS
113    cd['help_text'] = help_text
114