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