123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #!/usr/bin/env zsh
- #
- # Copyright 2017-2018 Henry Chang
- #
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- __zic_fzf_prog() {
- [ -n "$TMUX_PANE" ] && [ "${FZF_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] \
- && echo "fzf-tmux -d${FZF_TMUX_HEIGHT:-40%}" || echo "fzf"
- }
- __zic_matched_subdir_list() {
- local dir length seg starts_with_dir
- if [[ "$1" == */ ]]; then
- dir="$1"
- if [[ "$dir" != / ]]; then
- dir="${dir: : -1}"
- fi
- length=$(echo -n "$dir" | wc -c)
- if [ "$dir" = "/" ]; then
- length=0
- fi
- find -L "$dir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null \
- | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' | while read -r line; do
- if [[ "${line[1]}" == "." ]]; then
- continue
- fi
- echo "$line"
- done
- else
- dir=$(dirname -- "$1")
- length=$(echo -n "$dir" | wc -c)
- if [ "$dir" = "/" ]; then
- length=0
- fi
- seg=$(basename -- "$1")
- starts_with_dir=$( \
- find -L "$dir" -mindepth 1 -maxdepth 1 -type d \
- 2>/dev/null | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' \
- | while read -r line; do
- if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then
- continue
- fi
- if [ "$zic_case_insensitive" = "true" ]; then
- if [[ "$line:u" == "$seg:u"* ]]; then
- echo "$line"
- fi
- else
- if [[ "$line" == "$seg"* ]]; then
- echo "$line"
- fi
- fi
- done
- )
- if [ -n "$starts_with_dir" ]; then
- echo "$starts_with_dir"
- else
- find -L "$dir" -mindepth 1 -maxdepth 1 -type d \
- 2>/dev/null | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' \
- | while read -r line; do
- if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then
- continue
- fi
- if [ "$zic_case_insensitive" = "true" ]; then
- if [[ "$line:u" == *"$seg:u"* ]]; then
- echo "$line"
- fi
- else
- if [[ "$line" == *"$seg"* ]]; then
- echo "$line"
- fi
- fi
- done
- fi
- fi
- }
- __zic_fzf_bindings() {
- autoload is-at-least
- fzf=$(__zic_fzf_prog)
- if $(is-at-least '0.21.0' $(${=fzf} --version)); then
- echo 'shift-tab:up,tab:down,bspace:backward-delete-char/eof'
- else
- echo 'shift-tab:up,tab:down'
- fi
- }
- _zic_list_generator() {
- __zic_matched_subdir_list "${(Q)@[-1]}" | sort
- }
- _zic_complete() {
- setopt localoptions nonomatch
- local l matches fzf tokens base
- l=$(_zic_list_generator $@)
- if [ -z "$l" ]; then
- zle ${__zic_default_completion:-expand-or-complete}
- return
- fi
- fzf=$(__zic_fzf_prog)
- fzf_bindings=$(__zic_fzf_bindings)
- if [ $(echo $l | wc -l) -eq 1 ]; then
- matches=${(q)l}
- else
- matches=$(echo $l \
- | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} \
- --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS \
- --bind '${fzf_bindings}'" ${=fzf} \
- | while read -r item; do
- echo -n "${(q)item} "
- done)
- fi
- matches=${matches% }
- if [ -n "$matches" ]; then
- tokens=(${(z)LBUFFER})
- base="${(Q)@[-1]}"
- if [[ "$base" != */ ]]; then
- if [[ "$base" == */* ]]; then
- base="$(dirname -- "$base")"
- if [[ ${base[-1]} != / ]]; then
- base="$base/"
- fi
- else
- base=""
- fi
- fi
- LBUFFER="${tokens[1]} "
- if [ -n "$base" ]; then
- base="${(q)base}"
- if [ "${tokens[2][1]}" = "~" ]; then
- base="${base/#$HOME/~}"
- fi
- LBUFFER="${LBUFFER}${base}"
- fi
- LBUFFER="${LBUFFER}${matches}/"
- fi
- zle redisplay
- typeset -f zle-line-init >/dev/null && zle zle-line-init
- }
- zic-completion() {
- setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
- local tokens cmd
- tokens=(${(z)LBUFFER})
- cmd=${tokens[1]}
- if [[ "$LBUFFER" =~ "^\ *cd$" ]]; then
- zle ${__zic_default_completion:-expand-or-complete}
- elif [ "$cmd" = cd ]; then
- _zic_complete ${tokens[2,${#tokens}]/#\~/$HOME}
- else
- zle ${__zic_default_completion:-expand-or-complete}
- fi
- }
- [ -z "$__zic_default_completion" ] && {
- binding=$(bindkey '^I')
- # $binding[(s: :w)2]
- # The command substitution and following word splitting to determine the
- # default zle widget for ^I formerly only works if the IFS parameter contains
- # a space via $binding[(w)2]. Now it specifically splits at spaces, regardless
- # of IFS.
- [[ $binding =~ 'undefined-key' ]] || __zic_default_completion=$binding[(s: :w)2]
- unset binding
- }
- zle -N zic-completion
- if [ -z $zic_custom_binding ]; then
- zic_custom_binding='^I'
- fi
- bindkey "${zic_custom_binding}" zic-completion
|