Delegate kitty +kitten clipboard to kitty-tool
This commit is contained in:
parent
5eb2142d70
commit
375fa73826
@ -1,20 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
import codecs
|
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import select
|
|
||||||
import sys
|
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'''
|
OPTIONS = r'''
|
||||||
--get-clipboard
|
--get-clipboard
|
||||||
@ -45,103 +32,8 @@ popup, see :opt:`clipboard_control` for details.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
usage = ''
|
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__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv)
|
raise SystemExit('This should be run as kitty-tool clipboard')
|
||||||
elif __name__ == '__doc__':
|
elif __name__ == '__doc__':
|
||||||
cd = sys.cli_docs # type: ignore
|
cd = sys.cli_docs # type: ignore
|
||||||
cd['usage'] = usage
|
cd['usage'] = usage
|
||||||
|
|||||||
@ -316,19 +316,32 @@ ensure_working_stdio(void) {
|
|||||||
#undef C
|
#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
|
static void
|
||||||
delegate_to_kitty_tool_if_possible(int argc, char *argv[], char* exe_dir) {
|
delegate_to_kitty_tool_if_possible(int argc, char *argv[], char* exe_dir) {
|
||||||
if (argc > 1 && argv[1][0] == '@') {
|
if (argc > 1 && argv[1][0] == '@') exec_kitty_tool(argc, argv, exe_dir);
|
||||||
char exe[PATH_MAX+1] = {0};
|
if (argc > 2 && strcmp(argv[1], "+kitten") == 0 && is_wrapped_kitten(argv[2])) exec_kitty_tool(argc - 1, argv + 1, exe_dir);
|
||||||
snprintf(exe, PATH_MAX, "%s/kitty-tool", 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);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[], char* envp[]) {
|
int main(int argc, char *argv[], char* envp[]) {
|
||||||
|
|||||||
9
setup.py
9
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':
|
if src == 'kitty/parser_dump.c':
|
||||||
return 'kitty/parser.c', ['DUMP_COMMANDS']
|
return 'kitty/parser.c', ['DUMP_COMMANDS']
|
||||||
if src == 'kitty/data-types.c':
|
if src == 'kitty/data-types.c':
|
||||||
wk = ' '.join(wrapped_kittens())
|
return src, [f'KITTY_VCS_REV="{get_vcs_rev_define()}"', f'WRAPPED_KITTENS="{wrapped_kittens()}"']
|
||||||
return src, [f'KITTY_VCS_REV="{get_vcs_rev_define()}"', f'WRAPPED_KITTENS="{wk}"']
|
|
||||||
try:
|
try:
|
||||||
return src, env.library_paths[src]
|
return src, env.library_paths[src]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -863,12 +862,12 @@ def build_ref_map() -> str:
|
|||||||
|
|
||||||
|
|
||||||
@lru_cache
|
@lru_cache
|
||||||
def wrapped_kittens() -> Sequence[str]:
|
def wrapped_kittens() -> str:
|
||||||
with open('shell-integration/ssh/kitty') as f:
|
with open('shell-integration/ssh/kitty') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
if line.startswith(' wrapped_kittens="'):
|
if line.startswith(' wrapped_kittens="'):
|
||||||
val = line.strip().partition('"')[2][:-1]
|
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')
|
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:
|
def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 'source') -> None:
|
||||||
werror = '' if args.ignore_compiler_warnings else '-pedantic-errors -Werror'
|
werror = '' if args.ignore_compiler_warnings else '-pedantic-errors -Werror'
|
||||||
cflags = f'-Wall {werror} -fpie'.split()
|
cflags = f'-Wall {werror} -fpie'.split()
|
||||||
cppflags = []
|
cppflags = [define(f'WRAPPED_KITTENS=" {wrapped_kittens()} "')]
|
||||||
libs: List[str] = []
|
libs: List[str] = []
|
||||||
ldflags = shlex.split(os.environ.get('LDFLAGS', ''))
|
ldflags = shlex.split(os.environ.get('LDFLAGS', ''))
|
||||||
if args.profile or args.sanitize:
|
if args.profile or args.sanitize:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user