diff --git a/kittens/clipboard/main.py b/kittens/clipboard/main.py index dd7bd23ec..3aa26dbe2 100644 --- a/kittens/clipboard/main.py +++ b/kittens/clipboard/main.py @@ -1,20 +1,7 @@ #!/usr/bin/env python3 # License: GPL v3 Copyright: 2018, Kovid Goyal -import codecs -import io -import os -import select import sys -from typing import List, NoReturn, Optional - -from kitty.cli import parse_args -from kitty.cli_stub import ClipboardCLIOptions -from kitty.fast_data_types import parse_input_from_terminal - -from ..tui.operations import ( - raw_mode, request_from_clipboard, write_to_clipboard -) OPTIONS = r''' --get-clipboard @@ -45,103 +32,8 @@ popup, see :opt:`clipboard_control` for details. ''' usage = '' -got_capability_response = False -got_clipboard_response = False -clipboard_contents = '' -clipboard_from_primary = False - - -def ignore(x: str) -> None: - pass - - -def on_text(x: str) -> None: - if '\x03' in x: - raise KeyboardInterrupt() - if '\x04' in x: - raise EOFError() - - -def on_dcs(dcs: str) -> None: - global got_capability_response - if dcs.startswith('1+r'): - got_capability_response = True - - -def on_osc(osc: str) -> None: - global clipboard_contents, clipboard_from_primary, got_clipboard_response - idx = osc.find(';') - if idx <= 0: - return - q = osc[:idx] - if q == '52': - got_clipboard_response = True - widx = osc.find(';', idx + 1) - if widx < idx: - clipboard_from_primary = osc.find('p', idx + 1) > -1 - clipboard_contents = '' - else: - from base64 import standard_b64decode - clipboard_from_primary = osc.find('p', idx+1, widx) > -1 - data = memoryview(osc.encode('ascii')) - clipboard_contents = standard_b64decode(data[widx+1:]).decode('utf-8') - - -def wait_loop(tty_fd: int) -> None: - os.set_blocking(tty_fd, False) - decoder = codecs.getincrementaldecoder('utf-8')('ignore') - with raw_mode(tty_fd): - buf = '' - while not got_capability_response and not got_clipboard_response: - rd = select.select([tty_fd], [], [])[0] - if rd: - raw = os.read(tty_fd, io.DEFAULT_BUFFER_SIZE) - if not raw: - raise EOFError() - data = decoder.decode(raw) - buf = (buf + data) if buf else data - buf = parse_input_from_terminal(on_text, on_dcs, ignore, on_osc, ignore, ignore, buf, False) - - -def main(args: List[str]) -> NoReturn: - cli_opts, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard', result_class=ClipboardCLIOptions) - if items: - raise SystemExit('Unrecognized extra command line arguments') - data: Optional[bytes] = None - if not sys.stdin.isatty(): - data = sys.stdin.buffer.read() - wait_for_capability_response = False - data_to_write = [] - if data: - data_to_write.append(write_to_clipboard(data, cli_opts.use_primary).encode('ascii')) - if not cli_opts.get_clipboard and cli_opts.wait_for_completion: - data_to_write.append(b'\x1bP+q544e\x1b\\') - wait_for_capability_response = True - if cli_opts.get_clipboard: - data_to_write.append(request_from_clipboard(cli_opts.use_primary).encode('ascii')) - wait_for_capability_response = True - tty_fd = os.open(os.ctermid(), os.O_RDWR | os.O_CLOEXEC) - retcode = 0 - with open(tty_fd, 'wb', closefd=True) as ttyf: - for x in data_to_write: - ttyf.write(x) - ttyf.flush() - if wait_for_capability_response: - try: - wait_loop(tty_fd) - except KeyboardInterrupt: - sys.excepthook = lambda *a: None - raise - except EOFError: - retcode = 1 - if clipboard_contents: - print(end=clipboard_contents) - - raise SystemExit(retcode) - - if __name__ == '__main__': - main(sys.argv) + raise SystemExit('This should be run as kitty-tool clipboard') elif __name__ == '__doc__': cd = sys.cli_docs # type: ignore cd['usage'] = usage diff --git a/kitty/launcher/main.c b/kitty/launcher/main.c index 1fac3532a..6963fa7d2 100644 --- a/kitty/launcher/main.c +++ b/kitty/launcher/main.c @@ -316,19 +316,32 @@ ensure_working_stdio(void) { #undef C } +static bool +is_wrapped_kitten(const char *arg) { + char buf[64]; + snprintf(buf, sizeof(buf)-1, " %s ", arg); + return strstr(" " WRAPPED_KITTENS " ", buf); +} + +static void +exec_kitty_tool(int argc, char *argv[], char *exe_dir) { + char exe[PATH_MAX+1] = {0}; + snprintf(exe, PATH_MAX, "%s/kitty-tool", exe_dir); + char **newargv = malloc(sizeof(char*) * (argc + 1)); + memcpy(newargv, argv, sizeof(char*) * argc); + newargv[argc] = 0; + newargv[0] = "kitty-tool"; + errno = 0; + execv(exe, argv); + fprintf(stderr, "Failed to execute kitty-tool (%s) with error: %s\n", exe, strerror(errno)); + exit(1); +} + static void delegate_to_kitty_tool_if_possible(int argc, char *argv[], char* exe_dir) { - if (argc > 1 && argv[1][0] == '@') { - char exe[PATH_MAX+1] = {0}; - snprintf(exe, PATH_MAX, "%s/kitty-tool", exe_dir); - char **newargv = malloc(sizeof(char*) * (argc + 1)); - memcpy(newargv, argv, sizeof(char*) * argc); - newargv[argc] = 0; - errno = 0; - execv(exe, argv); - fprintf(stderr, "Failed to execute kitty-tool (%s) with error: %s\n", exe, strerror(errno)); - exit(1); - } + if (argc > 1 && argv[1][0] == '@') exec_kitty_tool(argc, argv, exe_dir); + if (argc > 2 && strcmp(argv[1], "+kitten") == 0 && is_wrapped_kitten(argv[2])) exec_kitty_tool(argc - 1, argv + 1, exe_dir); + if (argc > 3 && strcmp(argv[1], "+") == 0 && strcmp(argv[2], "kitten") == 0 && is_wrapped_kitten(argv[3])) exec_kitty_tool(argc - 2, argv + 2, exe_dir); } int main(int argc, char *argv[], char* envp[]) { diff --git a/setup.py b/setup.py index 75e2d0bb3..7de603a66 100755 --- a/setup.py +++ b/setup.py @@ -529,8 +529,7 @@ def get_source_specific_defines(env: Env, src: str) -> Tuple[str, Optional[List[ if src == 'kitty/parser_dump.c': return 'kitty/parser.c', ['DUMP_COMMANDS'] if src == 'kitty/data-types.c': - wk = ' '.join(wrapped_kittens()) - return src, [f'KITTY_VCS_REV="{get_vcs_rev_define()}"', f'WRAPPED_KITTENS="{wk}"'] + return src, [f'KITTY_VCS_REV="{get_vcs_rev_define()}"', f'WRAPPED_KITTENS="{wrapped_kittens()}"'] try: return src, env.library_paths[src] except KeyError: @@ -863,12 +862,12 @@ def build_ref_map() -> str: @lru_cache -def wrapped_kittens() -> Sequence[str]: +def wrapped_kittens() -> str: with open('shell-integration/ssh/kitty') as f: for line in f: if line.startswith(' wrapped_kittens="'): val = line.strip().partition('"')[2][:-1] - return tuple(sorted(filter(None, val.split()))) + return ' '.join(sorted(filter(None, val.split()))) raise Exception('Failed to read wrapped kittens from kitty wrapper script') @@ -965,7 +964,7 @@ def build_static_binaries(args: Options, launcher_dir: str) -> None: def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 'source') -> None: werror = '' if args.ignore_compiler_warnings else '-pedantic-errors -Werror' cflags = f'-Wall {werror} -fpie'.split() - cppflags = [] + cppflags = [define(f'WRAPPED_KITTENS=" {wrapped_kittens()} "')] libs: List[str] = [] ldflags = shlex.split(os.environ.get('LDFLAGS', '')) if args.profile or args.sanitize: