From 777823301463a25d191a6502d24f6ed3ab75cb86 Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Wed, 11 Sep 2024 23:15:25 -0600 Subject: [PATCH] Allow shell integration scripts to request prompt click events This is done via the `prompt-click-events` keyword in `$KITTY_SHELL_INTEGRATION`. Also adds the `$KITTY_SUPPORTS_PROMPT_CLICK_EVENTS` environment variable, which scripts can use to check for support before requesting click events. Note that the fish integration script is intentionally not modified, as the fish integration seems to be built-in in newer versions. --- docs/glossary.rst | 4 ++++ docs/shell-integration.rst | 8 ++++++++ kitty/child.py | 1 + kitty/options/utils.py | 2 +- shell-integration/bash/kitty.bash | 14 +++++++++++--- shell-integration/zsh/kitty-integration | 18 ++++++++++++++---- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 9fec5a5ae57..e20c5789a5d 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -224,6 +224,10 @@ Variables that kitty sets when running child programs Set when enabling :ref:`shell_integration`. It is automatically removed by the shell integration scripts. +.. envvar:: KITTY_SUPPORTS_PROMPT_CLICK_EVENTS + + Set in all kitty versions that support the `click_events=1` flag in :ref:`shell_integration`. + .. envvar:: ZDOTDIR Set when enabling :ref:`shell_integration` with :program:`zsh`, allowing diff --git a/docs/shell-integration.rst b/docs/shell-integration.rst index b403139fc26..2106dc1998d 100644 --- a/docs/shell-integration.rst +++ b/docs/shell-integration.rst @@ -101,6 +101,14 @@ no-sudo user, setting of environment variables at the command line is also allowed. Only if commands are restricted is this needed. +prompt-click-events + Direct the injected shell integration scripts to emit the `click_events=1` + flag (described below). This is intended to be set by user scripts/rc files + modifying :envvar:`KITTY_SHELL_INTEGRATION` rather than directly in the + :opt:`shell_integration` option. Those scripts should first check for the + :envvar:`KITTY_SUPPORTS_PROMPT_CLICK_EVENTS` environment variable, which is + only set in kitty versions supporting the `click_events` flag. + Note that for the fish shell, this does nothing. More ways to browse command output ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/kitty/child.py b/kitty/child.py index 55dbd5f1995..b72abd5e690 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -242,6 +242,7 @@ def get_final_env(self) -> dict[str, str]: env.update(self.env) env['TERM'] = opts.term env['COLORTERM'] = 'truecolor' + env['KITTY_SUPPORTS_PROMPT_CLICK_EVENTS'] = 1 env['KITTY_PID'] = getpid() env['KITTY_PUBLIC_KEY'] = boss.encryption_public_key if self.add_listen_on_env_var and boss.listening_on: diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 2a23447d34b..1a9a0f6d04f 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -983,7 +983,7 @@ def menu_map(val: str, current_val: Container[str]) -> Iterable[Tuple[Tuple[str, yield location, parts[1][idx+1:].lstrip() -allowed_shell_integration_values = frozenset({'enabled', 'disabled', 'no-rc', 'no-cursor', 'no-title', 'no-prompt-mark', 'no-complete', 'no-cwd', 'no-sudo'}) +allowed_shell_integration_values = frozenset({'enabled', 'disabled', 'no-rc', 'no-cursor', 'no-title', 'no-prompt-mark', 'no-complete', 'no-cwd', 'no-sudo', 'prompt-click-events'}) def shell_integration(x: str) -> FrozenSet[str]: diff --git a/shell-integration/bash/kitty.bash b/shell-integration/bash/kitty.bash index 52755fd68dd..60373282acd 100644 --- a/shell-integration/bash/kitty.bash +++ b/shell-integration/bash/kitty.bash @@ -110,6 +110,7 @@ _ksi_main() { "no-complete") _ksi_prompt[complete]='n';; "no-cwd") _ksi_prompt[cwd]='n';; "no-sudo") _ksi_prompt[sudo]='n';; + "prompt-click-events") _ksi_prompt[click_events]='y';; esac done IFS="$ifs" @@ -134,7 +135,14 @@ _ksi_main() { _ksi_set_mark start_suffix _ksi_set_mark end_suffix builtin unset -f _ksi_set_mark - _ksi_prompt[secondary_prompt]="\n${_ksi_prompt[start_secondary_mark]}\[\e]133;A;k=s\a\]${_ksi_prompt[end_secondary_mark]}" + + if [[ ${_ksi_prompt[click_events]} == y ]]; then + _ksi_prompt[mark_options]=';click_events=1' + else + _ksi_prompt[mark_options]='' + fi + + _ksi_prompt[secondary_prompt]="\n${_ksi_prompt[start_secondary_mark]}\[\e]133;A${_ksi_prompt[mark_options]};k=s\a\]${_ksi_prompt[end_secondary_mark]}" _ksi_prompt_command() { # we first remove any previously added kitty code from the prompt variables and then add @@ -236,8 +244,8 @@ _ksi_main() { # this can result in multiple D prompt marks or ones that dont # correspond to a cmd but kitty handles this gracefully, only # taking into account the first D after a C. - _ksi_prompt[ps1]+="\[\e]133;D;\$?\a\e]133;A\a\]" - _ksi_prompt[ps2]+="\[\e]133;A;k=s\a\]" + _ksi_prompt[ps1]+="\[\e]133;D;\$?\a\e]133;A${_ksi_prompt[mark_options]}\a\]" + _ksi_prompt[ps2]+="\[\e]133;A${_ksi_prompt[mark_options]};k=s\a\]" fi builtin alias edit-in-kitty="kitten edit-in-kitty" diff --git a/shell-integration/zsh/kitty-integration b/shell-integration/zsh/kitty-integration index 76459d47828..f31ca976617 100644 --- a/shell-integration/zsh/kitty-integration +++ b/shell-integration/zsh/kitty-integration @@ -123,6 +123,16 @@ _ksi_deferred_init() { # Enable semantic markup with OSC 133. if (( ! opt[(Ie)no-prompt-mark] )); then + if (( opt[(Ie)prompt-click-events] )); then + _ksi_mark_options() { + echo ';click_events=1' + } + else + _ksi_mark_options() { + echo '' + } + fi + _ksi_precmd() { builtin local -i cmd_status=$? builtin emulate -L zsh -o no_warn_create_global -o no_aliases @@ -150,7 +160,7 @@ _ksi_deferred_init() { fi fi - builtin local mark1=$'%{\e]133;A\a%}' + builtin local mark1=$'%{\e]133;A'$(_ksi_mark_options)'\a%}' if [[ -o prompt_percent ]]; then builtin typeset -g precmd_functions if [[ ${precmd_functions[-1]} == _ksi_precmd ]]; then @@ -160,7 +170,7 @@ _ksi_deferred_init() { # SIGCHLD if notify is set. Themes that update prompt # asynchronously from a `zle -F` handler might still remove our # marks. Oh well. - builtin local mark2=$'%{\e]133;A;k=s\a%}' + builtin local mark2=$'%{\e]133;A;k=s'$(_ksi_mark_options)'\a%}' # Add marks conditionally to avoid a situation where we have # several marks in place. These conditions can have false # positives and false negatives though. @@ -207,8 +217,8 @@ _ksi_deferred_init() { # our own prompt, user prompt, and our own prompt with user additions on # top. We cannot force prompt_subst on the user though, so we would # still need this code for the no_prompt_subst case. - PS1=${PS1//$'%{\e]133;A\a%}'} - PS2=${PS2//$'%{\e]133;A;k=s\a%}'} + PS1=${PS1//$'%{\e]133;A'$(_ksi_mark_options)'\a%}'} + PS2=${PS2//$'%{\e]133;A'$(_ksi_mark_options)';k=s\a%}'} # This will work incorrectly in the presence of a preexec hook that # prints. For example, if MichaelAquilina/zsh-you-should-use installs