From d53f8f24c47156590ad6596ef0a278098bb82859 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 27 Feb 2022 10:20:19 +0530 Subject: [PATCH] Fix #4757 Still have to do the fix for zsh/fish --- kitty/parser.c | 4 ++++ kitty/screen.c | 6 ++++++ kitty/screen.h | 1 + kitty/window.py | 14 ++++++++++++-- kitty_tests/__init__.py | 6 +++--- kitty_tests/shell_integration.py | 8 ++++++++ shell-integration/bash/kitty.bash | 3 ++- 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/kitty/parser.c b/kitty/parser.c index 97be57c9b..19c79eb70 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -406,6 +406,10 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) { START_DISPATCH DISPATCH_OSC(set_title); END_DISPATCH + case 22222: + START_DISPATCH + DISPATCH_OSC(set_title_base64); + END_DISPATCH case 4: case 104: START_DISPATCH diff --git a/kitty/screen.c b/kitty/screen.c index 85414fa9e..f748b70aa 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1967,6 +1967,12 @@ set_title(Screen *self, PyObject *title) { CALLBACK("title_changed", "O", title); } +void +set_title_base64(Screen *self, PyObject *title) { + CALLBACK("title_changed", "OO", title, Py_True); +} + + void desktop_notify(Screen *self, unsigned int osc_code, PyObject *data) { CALLBACK("desktop_notify", "IO", osc_code, data); diff --git a/kitty/screen.h b/kitty/screen.h index f557b71e2..3a64b4bfd 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -211,6 +211,7 @@ void screen_handle_print(Screen *, PyObject *cmd); void screen_designate_charset(Screen *, uint32_t which, uint32_t as); void screen_use_latin1(Screen *, bool); void set_title(Screen *self, PyObject*); +void set_title_base64(Screen *self, PyObject*); void desktop_notify(Screen *self, unsigned int, PyObject*); void set_icon(Screen *self, PyObject*); void set_dynamic_color(Screen *self, unsigned int code, PyObject*); diff --git a/kitty/window.py b/kitty/window.py index 7cc4fa27a..10a4087cb 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -57,6 +57,16 @@ if TYPE_CHECKING: from .file_transmission import FileTransmission +def process_title_from_child(title: str, is_base64: bool) -> str: + if is_base64: + from base64 import standard_b64decode + try: + title = standard_b64decode(title).decode('utf-8', 'replace') + except Exception: + title = 'undecodeable title' + return sanitize_title(title) + + class WindowDict(TypedDict): id: int is_focused: bool @@ -734,8 +744,8 @@ class Window: # Cancel IME composition after loses focus update_ime_position_for_window(self.id, False, True) - def title_changed(self, new_title: Optional[str]) -> None: - self.child_title = sanitize_title(new_title or self.default_title) + def title_changed(self, new_title: Optional[str], is_base64: bool = False) -> None: + self.child_title = process_title_from_child(new_title or self.default_title, is_base64) if self.override_title is None: self.title_updated() diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 1a678c931..5c387c29d 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -21,7 +21,7 @@ from kitty.options.parse import merge_result_dicts from kitty.options.types import Options, defaults from kitty.types import MouseEvent from kitty.utils import read_screen_size -from kitty.window import process_remote_print +from kitty.window import process_remote_print, process_title_from_child class Callbacks: @@ -32,8 +32,8 @@ class Callbacks: def write(self, data) -> None: self.wtcbuf += data - def title_changed(self, data) -> None: - self.titlebuf.append(data) + def title_changed(self, data, is_base64=False) -> None: + self.titlebuf.append(process_title_from_child(data, is_base64)) def icon_changed(self, data) -> None: self.iconbuf += data diff --git a/kitty_tests/shell_integration.py b/kitty_tests/shell_integration.py index ab0675953..0819f5e5d 100644 --- a/kitty_tests/shell_integration.py +++ b/kitty_tests/shell_integration.py @@ -266,6 +266,14 @@ PS1="{ps1}" pty.wait_till(lambda: pty.screen.cursor.shape == 0) pty.write_to_child('\x04') pty.wait_till(lambda: pty.screen.cursor.shape == CURSOR_BEAM) + pty.write_to_child('\x04') + pty.send_cmd_to_child('clear') + pty.wait_till(lambda: pty.callbacks.titlebuf) + with self.run_shell(shell='bash', rc=f'''PS1="{ps1}"''') as pty: + pty.callbacks.clear() + pty.send_cmd_to_child('printf "%s\x16\a%s" "a" "b"') + pty.wait_till(lambda: 'ab' in pty.screen_contents()) + self.ae(pty.screen_contents(), 'prompt> printf "%s^G%s" "a" "b"\nab') for ps1 in ('line1\\nline\\2\\prompt> ', 'line1\nprompt> ', 'line1\\nprompt> ',): with self.subTest(ps1=ps1), self.run_shell( diff --git a/shell-integration/bash/kitty.bash b/shell-integration/bash/kitty.bash index 07dc8baaf..11e3b5422 100644 --- a/shell-integration/bash/kitty.bash +++ b/shell-integration/bash/kitty.bash @@ -139,7 +139,8 @@ _ksi_main() { last_cmd=$(HISTTIMEFORMAT= builtin history 1) last_cmd="${last_cmd#*[[:digit:]]*[[:space:]]}" # remove leading history number last_cmd="${last_cmd#"${last_cmd%%[![:space:]]*}"}" # remove remaining leading whitespace - builtin printf "\e]2;%s\a" "${last_cmd}" + last_cmd=$(printf "%s" "$last_cmd" | base64 | tr -d \\n) + builtin printf "\e]22222;%s\a" "${last_cmd}" } _ksi_prompt[ps0_suffix]+='$(_ksi_get_current_command)' fi