From 219e53826b1764f977dd9fe60aea903f79ed66c1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 9 May 2024 12:03:02 +0530 Subject: [PATCH] More efficient encoding for cmdline in the prompt marking escape code --- docs/shell-integration.rst | 8 ++++---- kitty/window.py | 3 ++- kitty_tests/__init__.py | 3 ++- shell-integration/bash/kitty.bash | 4 +--- shell-integration/zsh/kitty-integration | 4 +--- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/shell-integration.rst b/docs/shell-integration.rst index 4043d7373..bb4ac115a 100644 --- a/docs/shell-integration.rst +++ b/docs/shell-integration.rst @@ -458,10 +458,10 @@ to control its behavior, separated by semi-colons. They are:: kitty also optionally supports sending the cmdline going to be executed with ``133;C`` as:: - 133;C;cmdline=cmdline as space separated hex encoded text + 133;C;cmdline=cmdline encoded by %q or - 133;C;cmdline_url=cmdline as UTF-8 URL escaped text + 133;C;cmdline_url=cmdline as UTF-8 URL %-escaped text -Here, *space separated hex encoded text* means every unicode codepoint of the -command line is encoded as 2-8 hex digits separated by spaces. +Here, *encoded by %q* means the encoding produced by the %q format to printf in +bash and similar shells. diff --git a/kitty/window.py b/kitty/window.py index 2eabf6306..42c54851e 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -115,6 +115,7 @@ from .utils import ( sanitize_for_bracketed_paste, sanitize_title, sanitize_url_for_dispay_to_user, + shlex_split, ) MatchPatternType = Union[Pattern[str], Tuple[Pattern[str], Optional[Pattern[str]]]] @@ -220,7 +221,7 @@ def compile_match_query(exp: str, is_simple: bool = True) -> MatchPatternType: def decode_cmdline(x: str) -> str: ctype, sep, val = x.partition('=') if ctype == 'cmdline': - return ''.join(chr(int(x, 16)) for x in val.split()) + return next(shlex_split(val, True)) if ctype == 'cmdline_url': from urllib.parse import unquote return unquote(val) diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 74ba5e600..40ffb17d0 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -15,6 +15,7 @@ import time from contextlib import contextmanager from functools import wraps from pty import CHILD, STDIN_FILENO, STDOUT_FILENO, fork +from typing import Optional from unittest import TestCase from kitty.config import finalize_keys, finalize_mouse_mappings @@ -64,7 +65,7 @@ class Callbacks: def color_profile_popped(self, x) -> None: pass - def cmd_output_marking(self, is_start: bool) -> None: + def cmd_output_marking(self, is_start: Optional[bool], data: str = '') -> None: pass def request_capabilities(self, q) -> None: diff --git a/shell-integration/bash/kitty.bash b/shell-integration/bash/kitty.bash index e45c96d96..9ab615429 100644 --- a/shell-integration/bash/kitty.bash +++ b/shell-integration/bash/kitty.bash @@ -204,9 +204,7 @@ _ksi_main() { builtin printf "\e]2;%s%s\a" "${_ksi_prompt[hostname_prefix]@P}" "${_ksi_prompt[last_cmd]//[[:cntrl:]]}" # remove any control characters fi if [[ "${_ksi_prompt[mark]}" == "y" ]]; then - builtin printf "\e]133;C;cmdline=" - for (( i=0; i<${#last_cmd}; i++ )); do builtin printf '%x ' "'${last_cmd:$i:1}"; done - builtin printf "\a" + builtin printf "\e]133;C;cmdline=%q\a" "$last_cmd" fi } if [[ "${_ksi_prompt[title]}" == "y" || "${_ksi_prompt[mark]}" ]]; then _ksi_prompt[ps0]+='$(_ksi_get_current_command)'; fi diff --git a/shell-integration/zsh/kitty-integration b/shell-integration/zsh/kitty-integration index 0905cdf1a..76459d478 100644 --- a/shell-integration/zsh/kitty-integration +++ b/shell-integration/zsh/kitty-integration @@ -215,9 +215,7 @@ _ksi_deferred_init() { # its preexec hook before us, we'll incorrectly mark its output as # belonging to the command (as if the user typed it into zle) rather # than command output. - builtin print -nu "$_ksi_fd" '\e]133;C;cmdline=' - for (( i=0; i<${#1}; i++ )); do builtin print -nu "$_ksi_fd" -f '%x ' "'${1:$i:1}"; done - builtin print -nu "$_ksi_fd" '\a' + builtin print -nu "$_ksi_fd" -f '\e]133;C;cmdline=%q\a' "$1" (( _ksi_state = 1 )) }