# ____ ____ # / __/___ / __/ # / /_/_ / / /_ # / __/ / /_/ __/ # /_/ /___/_/ key-bindings.zsh # # - $FZF_TMUX_OPTS # - $FZF_CTRL_T_COMMAND # - $FZF_CTRL_T_OPTS # - $FZF_CTRL_R_OPTS # - $FZF_ALT_C_COMMAND # - $FZF_ALT_C_OPTS # Key bindings # ------------ # The code at the top and the bottom of this file is the same as in completion.zsh. # Refer to that file for explanation. if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then __fzf_key_bindings_options="options=(${(j: :)${(kv)options[@]}})" else () { __fzf_key_bindings_options="setopt" 'local' '__fzf_opt' for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do if [[ -o "$__fzf_opt" ]]; then __fzf_key_bindings_options+=" -o $__fzf_opt" else __fzf_key_bindings_options+=" +o $__fzf_opt" fi done } fi 'builtin' 'emulate' 'zsh' && 'builtin' 'setopt' 'no_aliases' { if [[ -o interactive ]]; then __fzf_defaults() { # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS echo -E "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1" command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null echo -E "${FZF_DEFAULT_OPTS-} $2" } # This function performs `exec awk "$@"` safely by working around awk # compatibility issues. # # Note: To reduce an extra fork, this function performs "exec" so is expected # to be run as the last command in a subshell. # # Note: This function is included with {completion,key-bindings}.{bash,zsh} and # synchronized. __fzf_exec_awk() { if [[ -z ${__fzf_awk-} ]]; then __fzf_awk=awk if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then # Note: Solaris awk at /usr/bin/awk is meant for backward compatibility # with an ancient implementation of 1977 awk in the original UNIX. It # lacks many features of POSIX awk, so it is essentially useless in the # modern point of view. To use a standard-conforming version in Solaris, # one needs to explicitly use /usr/xpg4/bin/awk. __fzf_awk=/usr/xpg4/bin/awk else # choose the faster mawk if: it's installed && build date >= 20230322 && # version >= 1.3.4 local n x y z d IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null) [[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk fi fi # Note: macOS awk has a quirk that it stops processing at all when it sees # any data not following UTF-8 in the input stream when the current LC_CTYPE # specifies the UTF-8 encoding. To work around this quirk, one needs to # specify LC_ALL=C to change the current encoding to the plain one. LC_ALL=C exec "$__fzf_awk" "$@" } # CTRL-T - Paste the selected file path(s) into the command line __fzf_select() { setopt localoptions pipefail no_aliases 2> /dev/null local item FZF_DEFAULT_COMMAND=${FZF_CTRL_T_COMMAND:-} \ FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path" "${FZF_CTRL_T_OPTS-} -m") \ FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) "$@" < /dev/tty | while read -r item; do echo -n -E "${(q)item} " done local ret=$? echo return $ret } __fzfcmd() { [ -n "${TMUX_PANE-}" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "${FZF_TMUX_OPTS-}" ]; } && echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf" } fzf-file-widget() { LBUFFER="${LBUFFER}$(__fzf_select)" local ret=$? zle reset-prompt return $ret } if [[ "${FZF_CTRL_T_COMMAND-x}" != "" ]]; then zle -N fzf-file-widget bindkey -M emacs '^T' fzf-file-widget bindkey -M vicmd '^T' fzf-file-widget bindkey -M viins '^T' fzf-file-widget fi # ALT-C - cd into the selected directory fzf-cd-widget() { setopt localoptions pipefail no_aliases 2> /dev/null local dir="$( FZF_DEFAULT_COMMAND=${FZF_ALT_C_COMMAND:-} \ FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path" "${FZF_ALT_C_OPTS-} +m") \ FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) < /dev/tty)" if [[ -z "$dir" ]]; then zle redisplay return 0 fi zle push-line # Clear buffer. Auto-restored on next prompt. BUFFER="builtin cd -- ${(q)dir:a}" zle accept-line local ret=$? unset dir # ensure this doesn't end up appearing in prompt expansion zle reset-prompt return $ret } if [[ "${FZF_ALT_C_COMMAND-x}" != "" ]]; then zle -N fzf-cd-widget bindkey -M emacs '\ec' fzf-cd-widget bindkey -M vicmd '\ec' fzf-cd-widget bindkey -M viins '\ec' fzf-cd-widget fi # CTRL-R - Paste the selected command from history into the command line fzf-history-widget() { local selected setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases noglob nobash_rematch 2> /dev/null # Ensure the module is loaded if not already, and the required features, such # as the associative 'history' array, which maps event numbers to full history # lines, are set. Also, make sure Perl is installed for multi-line output. if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then selected="$(printf '%s\t%s\000' "${(kv)history[@]}" | perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' | FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \ FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))" else selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' | FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \ FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))" fi local ret=$? if [ -n "$selected" ]; then if [[ $(__fzf_exec_awk '{print $1; exit}' <<< "$selected") =~ ^[1-9][0-9]* ]]; then zle vi-fetch-history -n $MATCH else # selected is a custom query, not from history LBUFFER="$selected" fi fi zle reset-prompt return $ret } zle -N fzf-history-widget bindkey -M emacs '^R' fzf-history-widget bindkey -M vicmd '^R' fzf-history-widget bindkey -M viins '^R' fzf-history-widget fi } always { eval $__fzf_key_bindings_options 'unset' '__fzf_key_bindings_options' }