diff --git a/kitty/file_transmission.py b/kitty/file_transmission.py new file mode 100644 index 000000000..0d406502a --- /dev/null +++ b/kitty/file_transmission.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + +from enum import Enum, auto +from base64 import standard_b64decode + + +class Action(Enum): + send = auto() + data = auto() + receive = auto() + invalid = auto() + + +class FileTransmissionCommand: + + action = Action.invalid + id: str = '' + secret: str = '' + + payload = b'' + + +def parse_command(data: str) -> FileTransmissionCommand: + parts = data.split(':', 1) + ans = FileTransmissionCommand() + if len(parts) == 1: + control, payload = parts[0], '' + else: + control, payload = parts + ans.payload = standard_b64decode(payload) + + for x in control.split(','): + k, v = x.partition('=')[::2] + if k == 'action': + ans.action = Action[v] + elif k == 'id': + ans.id = v + elif k == 'secret': + ans.secret = v + + if ans.action is Action.invalid: + raise ValueError('No valid action specified in file transmission command') + + return ans diff --git a/kitty/parser.c b/kitty/parser.c index b1258a13d..aa6e8831d 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -445,6 +445,10 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { START_DISPATCH DISPATCH_OSC(shell_prompt_marking); END_DISPATCH + case 5113: + START_DISPATCH + DISPATCH_OSC(file_transmission); + END_DISPATCH case 30001: REPORT_COMMAND(screen_push_dynamic_colors); screen_push_colors(screen, 0); diff --git a/kitty/screen.c b/kitty/screen.c index 048b6cc77..c531346e5 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1786,6 +1786,12 @@ clipboard_control(Screen *self, int code, PyObject *data) { CALLBACK("clipboard_control", "OO", data, code == -52 ? Py_True: Py_False); } +void +file_transmission(Screen *self, PyObject *data) { + if (PyUnicode_READY(data) != 0) { PyErr_Clear(); return; } + CALLBACK("file_transmission", "O", data); +} + void shell_prompt_marking(Screen *self, PyObject *data) { if (PyUnicode_READY(data) != 0) { PyErr_Clear(); return; } diff --git a/kitty/screen.h b/kitty/screen.h index cb1f0dfea..c705aad94 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -199,6 +199,7 @@ void set_icon(Screen *self, PyObject*); void set_dynamic_color(Screen *self, unsigned int code, PyObject*); void clipboard_control(Screen *self, int code, PyObject*); void shell_prompt_marking(Screen *self, PyObject*); +void file_transmission(Screen *self, PyObject*); void set_color_table_color(Screen *self, unsigned int code, PyObject*); void process_cwd_notification(Screen *self, unsigned int code, PyObject*); uint32_t* translation_table(uint32_t which); diff --git a/kitty/window.py b/kitty/window.py index 4a96f3ac6..de8ef02ff 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -799,6 +799,10 @@ class Window: def send_cmd_response(self, response: Any) -> None: self.screen.send_escape_code_to_child(DCS, '@kitty-cmd' + json.dumps(response)) + def file_transmission(self, data: str) -> None: + from .file_transmission import parse_command + parse_command(data) + def clipboard_control(self, data: str, is_partial: bool = False) -> None: where, text = data.partition(';')[::2] if is_partial: