Unfunction kitty-integration in zsh

This commit is contained in:
Roman Perepelitsa
2021-12-23 18:13:49 +01:00
parent 59505d17d5
commit 9bba38bd11
3 changed files with 210 additions and 217 deletions

View File

@@ -33,6 +33,7 @@ fi
if [[ -r "$_ksi_file" ]]; then if [[ -r "$_ksi_file" ]]; then
'builtin' 'autoload' '-Uz' '--' "$_ksi_file" 'builtin' 'autoload' '-Uz' '--' "$_ksi_file"
"${_ksi_file:t}" "${_ksi_file:t}"
'builtin' 'unfunction' '--' "${_ksi_file:t}"
fi fi
fi fi
'builtin' 'unset' '_ksi_file' 'builtin' 'unset' '_ksi_file'

View File

@@ -12,6 +12,7 @@
# if [[ -n $KITTY_INSTALLATION_DIR ]]; then # if [[ -n $KITTY_INSTALLATION_DIR ]]; then
# autoload -Uz -- "$KITTY_INSTALLATION_DIR"/shell-integration/zsh/kitty-integration # autoload -Uz -- "$KITTY_INSTALLATION_DIR"/shell-integration/zsh/kitty-integration
# kitty-integration # kitty-integration
# unfunction kitty-integration
# fi # fi
# #
# Implementation note: We can assume that alias expansion is disabled in this # Implementation note: We can assume that alias expansion is disabled in this
@@ -23,60 +24,48 @@ builtin emulate -L zsh -o no_warn_create_global
[[ -o interactive ]] || builtin return 0 # non-interactive shell [[ -o interactive ]] || builtin return 0 # non-interactive shell
[[ -n $KITTY_SHELL_INTEGRATION ]] || builtin return 0 # integration disabled [[ -n $KITTY_SHELL_INTEGRATION ]] || builtin return 0 # integration disabled
(( ! _ksi_state )) || builtin return 0 # already initialized (( ! $+_ksi_state )) || builtin return 0 # already initialized
if (( ! $+_ksi_state )); then # 0: no OSC 133 [AC] marks have been written yet.
# 0: not initialized; deferred initialization can start now. # 1: the last written OSC 133 C has not been closed with D yet.
# 1: not initialized; waiting for deferred initialization. # 2: none of the above.
# 2: initialized; no OSC 133 [AC] marks have been written yet. builtin typeset -gi _ksi_state
# 3: initialized; the last written OSC 133 C has not been closed with D yet.
# 4: initialized; none of the above.
builtin typeset -gi _ksi_state=1
# Asks Kitty to print $@ to its stdout. This is for debugging. # Asks Kitty to print $@ to its stdout. This is for debugging.
_ksi_debug_print() { _ksi_debug_print() {
builtin local data builtin local data
data=$(command base64 <<<"${(j: :}@}") || builtin return data=$(command base64 <<<"${(j: :}@}") || builtin return
builtin printf '\eP@kitty-print|%s\e\\' "${data//$'\n'}" builtin printf '\eP@kitty-print|%s\e\\' "${data//$'\n'}"
} }
_ksi_deferred_init() { # We defer initialization until precmd for several reasons:
(( _ksi_state = 0, 1 )) # `, 1` in case err_return is set #
kitty-integration # - Oh My Zsh and many other configs remove zle-line-init and
} # zle-line-finish hooks when they initialize.
# - By deferring initialization we allow user rc files to opt out from some
# parts of integration. For example, if a zshrc theme prints OSC 133
# marks, it can append " no-prompt-mark" to KITTY_SHELL_INTEGRATION during
# intialization to avoid redundant marks from our code.
builtin typeset -ag precmd_functions
precmd_functions+=(_ksi_deferred_init)
# We defer initialization until precmd for several reasons: _ksi_deferred_init() {
# builtin emulate -L zsh -o no_warn_create_global
# - Oh My Zsh and many other configs remove zle-line-init and
# zle-line-finish hooks when they initialize.
# - By deferring initialization we allow user rc files to opt out from some
# parts of integration. For example, if a zshrc theme prints OSC 133
# marks, it can append " no-prompt-mark" to KITTY_SHELL_INTEGRATION during
# intialization to avoid redundant marks from our code.
builtin typeset -ag precmd_functions
precmd_functions+=(_ksi_deferred_init)
builtin return
fi
# The rest of kitty-integration performs deferred initialization. We are being # Recognized options: no-cursor, no-title, no-prompt-mark, no-complete.
# run from _ksi_deferred_init here. builtin local -a opt
opt=(${(s: :)KITTY_SHELL_INTEGRATION})
unset KITTY_SHELL_INTEGRATION
(( _ksi_state = 2 )) # The directory where kitty-integration is located: /.../shell-integration/zsh.
builtin local self_dir=${functions_source[kitty-integration]:A:h}
# The directory with _kitty. We store it in a directory of its own rather than
# in $self_dir because we are adding it to fpath and we don't want any other
# files to be accidentally autoloadable.
builtin local comp_dir=$self_dir/completions
# Recognized options: no-cursor, no-title, no-prompt-mark, no-complete. # Enable completions for `kitty` command.
builtin local -a opt if (( ! opt[(Ie)no-complete] )) && [[ -r $comp_dir/_kitty ]]; then
opt=(${(s: :)KITTY_SHELL_INTEGRATION})
unset KITTY_SHELL_INTEGRATION
# The directory where kitty-integration is located: /.../shell-integration/zsh.
builtin local self_dir=${functions_source[kitty-integration]:A:h}
# The directory with _kitty. We store it in a directory of its own rather than
# in $self_dir because we are adding it to fpath and we don't want any other
# files to be accidentally autoloadable.
builtin local comp_dir=$self_dir/completions
# Enable completions for `kitty` command.
if (( ! opt[(Ie)no-complete] )) && [[ -r $comp_dir/_kitty ]]; then
if (( $+functions[compdef] )); then if (( $+functions[compdef] )); then
# If compdef is defined, then either compinit has already run or it's # If compdef is defined, then either compinit has already run or it's
# a shim that records all calls for the purpose of replaying them after # a shim that records all calls for the purpose of replaying them after
@@ -96,10 +85,10 @@ if (( ! opt[(Ie)no-complete] )) && [[ -r $comp_dir/_kitty ]]; then
# mapping. # mapping.
builtin typeset -ga fpath builtin typeset -ga fpath
fpath=($comp_dir ${fpath:#$comp_dir}) fpath=($comp_dir ${fpath:#$comp_dir})
fi fi
# Enable cursor shape changes depending on the current keymap. # Enable cursor shape changes depending on the current keymap.
if (( ! opt[(Ie)no-cursor] )); then if (( ! opt[(Ie)no-cursor] )); then
# This implementation leaks blinking block cursor into external commands # This implementation leaks blinking block cursor into external commands
# executed from zle. For example, users of fzf-based widgets may find # executed from zle. For example, users of fzf-based widgets may find
# themselves with a blinking block cursor within fzf. # themselves with a blinking block cursor within fzf.
@@ -109,10 +98,10 @@ if (( ! opt[(Ie)no-cursor] )); then
*) builtin print -n '\e[5 q';; # blinking bar cursor *) builtin print -n '\e[5 q';; # blinking bar cursor
esac esac
} }
fi fi
# Enable semantic markup with OSC 133. # Enable semantic markup with OSC 133.
if (( ! opt[(Ie)no-prompt-mark] )); then if (( ! opt[(Ie)no-prompt-mark] )); then
_ksi_precmd() { _ksi_precmd() {
builtin local -i cmd_status=$? builtin local -i cmd_status=$?
builtin emulate -L zsh -o no_warn_create_global builtin emulate -L zsh -o no_warn_create_global
@@ -129,12 +118,12 @@ if (( ! opt[(Ie)no-prompt-mark] )); then
# with LF and prompst_sp is set (it is by default). In this case # with LF and prompst_sp is set (it is by default). In this case
# we'll incorrectly state that '%' from prompt_sp is a part of the # we'll incorrectly state that '%' from prompt_sp is a part of the
# command's output. # command's output.
if (( _ksi_state == 3 )); then if (( _ksi_state == 1 )); then
# The last written OSC 133 C has not been closed with D yet. # The last written OSC 133 C has not been closed with D yet.
# Close it and supply status. # Close it and supply status.
builtin printf '\e]133;D;%s\a' $cmd_status builtin printf '\e]133;D;%s\a' $cmd_status
(( _ksi_state = 4 )) (( _ksi_state = 2 ))
elif (( _ksi_state == 4 )); then elif (( _ksi_state == 2 )); then
# There might be an unclosed OSC 133 C. Close that. # There might be an unclosed OSC 133 C. Close that.
builtin print -n '\e]133;D\a' builtin print -n '\e]133;D\a'
fi fi
@@ -159,7 +148,7 @@ if (( ! opt[(Ie)no-prompt-mark] )); then
# - False negative (with prompt_subst): PS1='$mark1' # - False negative (with prompt_subst): PS1='$mark1'
[[ $PS1 == *$mark1* ]] || PS1=${mark1}${PS1} [[ $PS1 == *$mark1* ]] || PS1=${mark1}${PS1}
[[ $PS2 == *$mark2* ]] || PS2=${mark2}${PS2} [[ $PS2 == *$mark2* ]] || PS2=${mark2}${PS2}
(( _ksi_state = 4 )) (( _ksi_state = 2 ))
else else
# If our precmd hook is not the last, we cannot rely on prompt # If our precmd hook is not the last, we cannot rely on prompt
# changes to stick, so we don't even try. At least we can move # changes to stick, so we don't even try. At least we can move
@@ -175,7 +164,7 @@ if (( ! opt[(Ie)no-prompt-mark] )); then
# it. If it doesn't, there is nothing we can do. # it. If it doesn't, there is nothing we can do.
if ! builtin zle; then if ! builtin zle; then
builtin print -rn -- $mark1[3,-3] builtin print -rn -- $mark1[3,-3]
(( _ksi_state = 4 )) (( _ksi_state = 2 ))
fi fi
fi fi
elif ! builtin zle; then elif ! builtin zle; then
@@ -183,7 +172,7 @@ if (( ! opt[(Ie)no-prompt-mark] )); then
# mark, except when we are invoked from zle. In the latter case we # mark, except when we are invoked from zle. In the latter case we
# cannot do anything. # cannot do anything.
builtin print -rn -- $mark1[3,-3] builtin print -rn -- $mark1[3,-3]
(( _ksi_state = 4 )) (( _ksi_state = 2 ))
fi fi
} }
@@ -205,15 +194,15 @@ if (( ! opt[(Ie)no-prompt-mark] )); then
# belonging to the command (as if the user typed it into zle) rather # belonging to the command (as if the user typed it into zle) rather
# than command output. # than command output.
builtin print -n '\e]133;C\a' builtin print -n '\e]133;C\a'
(( _ksi_state = 3 )) (( _ksi_state = 1 ))
} }
functions[_ksi_zle_line_init]+=' functions[_ksi_zle_line_init]+='
builtin print -n "\\e]133;B\\a"' builtin print -n "\\e]133;B\\a"'
fi fi
# Enable terminal title changes. # Enable terminal title changes.
if (( ! opt[(Ie)no-title] )); then if (( ! opt[(Ie)no-title] )); then
# We don't use `print -P` because it depends on prompt options, which # We don't use `print -P` because it depends on prompt options, which
# we don't control and cannot change. # we don't control and cannot change.
# #
@@ -224,43 +213,45 @@ if (( ! opt[(Ie)no-title] )); then
builtin printf "\\e]2;%s\\a" "${(%):-%(4~|…/%3~|%~)}"' builtin printf "\\e]2;%s\\a" "${(%):-%(4~|…/%3~|%~)}"'
functions[_ksi_preexec]+=' functions[_ksi_preexec]+='
builtin printf "\\e]2;%s\\a" "${(V)1}"' builtin printf "\\e]2;%s\\a" "${(V)1}"'
fi fi
# Some zsh users manually run `source ~/.zshrc` in order to apply rc file # Some zsh users manually run `source ~/.zshrc` in order to apply rc file
# changes to the current shell. This is a terrible practice that breaks many # changes to the current shell. This is a terrible practice that breaks many
# things, including our shell integration. For example, Oh My Zsh and Prezto # things, including our shell integration. For example, Oh My Zsh and Prezto
# (both very popular among zsh users) will remove zle-line-init and # (both very popular among zsh users) will remove zle-line-init and
# zle-line-finish hooks if .zshrc is manually sourced. Prezto will also remove # zle-line-finish hooks if .zshrc is manually sourced. Prezto will also remove
# zle-keymap-select. # zle-keymap-select.
# #
# Another common (and much more robust) way to apply rc file changes to the # Another common (and much more robust) way to apply rc file changes to the
# current shell is `exec zsh`. This will remove our integration from the shell # current shell is `exec zsh`. This will remove our integration from the shell
# unless it's explicitly invoked from .zshrc. This is not an issue with # unless it's explicitly invoked from .zshrc. This is not an issue with
# `exec zsh` but rather with our implementation of automatic shell integration. # `exec zsh` but rather with our implementation of automatic shell integration.
builtin autoload -Uz add-zle-hook-widget builtin autoload -Uz add-zle-hook-widget
if (( $+functions[_ksi_zle_line_init] )); then if (( $+functions[_ksi_zle_line_init] )); then
add-zle-hook-widget line-init _ksi_zle_line_init add-zle-hook-widget line-init _ksi_zle_line_init
fi fi
if (( $+functions[_ksi_zle_line_finish] )); then if (( $+functions[_ksi_zle_line_finish] )); then
add-zle-hook-widget line-finish _ksi_zle_line_finish add-zle-hook-widget line-finish _ksi_zle_line_finish
fi fi
if (( $+functions[_ksi_zle_keymap_select] )); then if (( $+functions[_ksi_zle_keymap_select] )); then
add-zle-hook-widget keymap-select _ksi_zle_keymap_select add-zle-hook-widget keymap-select _ksi_zle_keymap_select
fi fi
if (( $+functions[_ksi_preexec] )); then if (( $+functions[_ksi_preexec] )); then
builtin typeset -ag preexec_functions builtin typeset -ag preexec_functions
preexec_functions+=(_ksi_preexec) preexec_functions+=(_ksi_preexec)
fi fi
builtin typeset -ag precmd_functions builtin typeset -ag precmd_functions
if (( $+functions[_ksi_precmd] )); then if (( $+functions[_ksi_precmd] )); then
precmd_functions=(${precmd_functions:/_ksi_deferred_init/_ksi_precmd}) precmd_functions=(${precmd_functions:/_ksi_deferred_init/_ksi_precmd})
_ksi_precmd _ksi_precmd
else else
precmd_functions=(${precmd_functions:#_ksi_deferred_init}) precmd_functions=(${precmd_functions:#_ksi_deferred_init})
fi fi
# Unfunction what we don't need to save memory. # Unfunction _ksi_deferred_init to save memory. Don't unfunction
builtin unfunction _ksi_deferred_init kitty-integration # kitty-integration though because decent public functions aren't supposed to
builtin autoload -Uz -- $self_dir/kitty-integration # to unfunction themselves when invoked.
builtin unfunction _ksi_deferred_init
}

View File

@@ -16,5 +16,6 @@
if [[ -r "$_ksi_file" ]]; then if [[ -r "$_ksi_file" ]]; then
'builtin' 'autoload' '-Uz' '--' "$_ksi_file" 'builtin' 'autoload' '-Uz' '--' "$_ksi_file"
"${_ksi_file:t}" "${_ksi_file:t}"
'builtin' 'unfunction' '--' "${_ksi_file:t}"
fi fi
'builtin' 'unset' '_ksi_file' 'builtin' 'unset' '_ksi_file'