diff --git a/config/zsh/.zshrc b/config/zsh/.zshrc index 00647d1..095a7ba 100644 --- a/config/zsh/.zshrc +++ b/config/zsh/.zshrc @@ -147,7 +147,6 @@ setup_zle() { ############################# # ZLE Widgets ############################# - set-cursor-shape() { local block='\e[1 q' # blinking block local underline='\e[3 q' # blinking underline, 4 for steady @@ -225,13 +224,8 @@ setup_zle() { ############################# # fzf ############################# - if type -p fzf >/dev/null; then - local fzf_config="$ZDOTDIR/fzf-key-bindings.zsh" - [ -r "$fzf_config" ] && source "$fzf_config" - export FZF_CTRL_T_OPTS=--border-label='" Select file(s) "' - export FZF_CTRL_R_OPTS=--border-label='" History search "' - export FZF_ALT_C_OPTS=--border-label='" Change directory "' + setup_zle_fzf else # Fall back to incremental search bindkey -M viins '^r' history-incremental-search-backward @@ -241,6 +235,55 @@ setup_zle() { fi } +setup_zle_fzf() { + local fzf_config="$ZDOTDIR/fzf/key-bindings.zsh" + [ -r "$fzf_config" ] || return + + fzf_find() { + local excluded_dirs=("-name '.*'") # Exclude hidden directories. + if [ "$(uname -s)" = "Darwin" ] && [ "$(pwd)" = "$HOME" ]; then + # These macOS directories would make the find command unusable (too slow). + excluded_dirs+=( + "-name Library" + "-name Movies" + "-name Music" + "-name Pictures" + ) + fi + + local excluded_filesystems=( + "-fstype devfs" + "-fstype devtmpfs" + "-fstype proc" + "-fstype sysfs" + ) + + local excluded_items=( + "-type d \\( ${(j: -o :)excluded_dirs} \\)" + "${(j: -o :)excluded_filesystems}" + ) + + local excluded="\\( ${(j: -o :)excluded_items} \\) -prune" + local included="\\( ${(j: -o :)@} \\) -print" + eval "command find -L . -mindepth 1 $excluded -o $included 2>/dev/null | cut -c3-" + } + + fzf_find_files() { + fzf_find "-type d" "-type f" + } + + fzf_find_dirs() { + fzf_find "-type d" + } + + source "$fzf_config" + export FZF_CTRL_T_COMMAND=fzf_find_files + export FZF_ALT_C_COMMAND=fzf_find_dirs + export FZF_CTRL_T_OPTS=--border-label='" Select file(s) "' + export FZF_CTRL_R_OPTS=--border-label='" History search "' + export FZF_ALT_C_OPTS=--border-label='" Change directory "' +} + # Colorful man pages. setup_man_pages() { # Foreground colors diff --git a/config/zsh/fzf-key-bindings.zsh b/config/zsh/fzf/key-bindings.zsh similarity index 75% rename from config/zsh/fzf-key-bindings.zsh rename to config/zsh/fzf/key-bindings.zsh index 83f4e5b..7d0a14d 100644 --- a/config/zsh/fzf-key-bindings.zsh +++ b/config/zsh/fzf/key-bindings.zsh @@ -11,6 +11,9 @@ # - $FZF_ALT_C_COMMAND # - $FZF_ALT_C_OPTS +[[ -o interactive ]] || return 0 + + # Key bindings # ------------ @@ -32,21 +35,19 @@ else } fi -'emulate' 'zsh' '-o' 'no_aliases' +'builtin' 'emulate' 'zsh' && 'builtin' 'setopt' 'no_aliases' { -[[ -o interactive ]] || return 0 - # CTRL-T - Paste the selected file path(s) into the command line __fsel() { - local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \ + local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \ -o -type f -print \ -o -type d -print \ -o -type l -print 2> /dev/null | cut -b3-"}" setopt localoptions pipefail no_aliases 2> /dev/null local item - eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-}" $(__fzfcmd) -m "$@" | while read item; do + eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --scheme=path --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_CTRL_T_OPTS-}" $(__fzfcmd) -m "$@" | while read item; do echo -n "${(q)item} " done local ret=$? @@ -72,10 +73,10 @@ bindkey -M viins '^T' fzf-file-widget # ALT-C - cd into the selected directory fzf-cd-widget() { - local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \ + local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \ -o -type d -print 2> /dev/null | cut -b3-"}" setopt localoptions pipefail no_aliases 2> /dev/null - local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m)" + local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --scheme=path --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m)" if [[ -z "$dir" ]]; then zle redisplay return 0 @@ -97,13 +98,15 @@ bindkey -M viins '\ec' fzf-cd-widget fzf-history-widget() { local selected num setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null - selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' | - FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} ${FZF_DEFAULT_OPTS-} -n2..,.. --tiebreak=index --reverse --bind=ctrl-r:toggle-sort,ctrl-z:ignore ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) ) + selected="$(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' | + FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} ${FZF_DEFAULT_OPTS-} -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m" $(__fzfcmd))" local ret=$? if [ -n "$selected" ]; then - num=$selected[1] - if [ -n "$num" ]; then - zle vi-fetch-history -n $num + num=$(awk '{print $1}' <<< "$selected") + if [[ "$num" =~ '^[1-9][0-9]*\*?$' ]]; then + zle vi-fetch-history -n ${num%\*} + else # selected is a custom query, not from history + LBUFFER="$selected" fi fi zle reset-prompt