1
0
Fork 0
mirror of https://github.com/ohmyzsh/ohmyzsh.git synced 2024-11-21 21:30:09 +00:00

Add zsh-interactive-cd plugin

This commit is contained in:
Henry Chang 2017-03-26 18:29:36 -07:00 committed by Marc Cornellà
parent e178ae39b4
commit 3ec04997eb
2 changed files with 170 additions and 0 deletions

View file

@ -0,0 +1,23 @@
# zsh-interactive-cd
This plugin adds a fish-like interactive tab completion for the `cd` command.
To use it, add `zsh-interactive-cd` to the plugins array of your zshrc file:
```zsh
plugins=(... zsh-interactive-cd)
```
![demo](https://user-images.githubusercontent.com/1441704/74360670-cb202900-4dc5-11ea-9734-f60caf726e85.gif)
## Usage
Press tab for completion as usual, it'll launch fzf automatically. Check fzfs [readme](https://github.com/junegunn/fzf#search-syntax) for more search syntax usage.
## Requirements
This plugin requires [fzf](https://github.com/junegunn/fzf). Install it by following
its [installation instructions](https://github.com/junegunn/fzf#installation).
## Author
[Henry Chang](https://github.com/changyuheng)

View file

@ -0,0 +1,147 @@
# Copyright (c) 2017 Henry Chang
__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 ))- | 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 ))- | sed '/^$/d' \
| while read -r line; do
if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then
continue
fi
if [[ "$line" == "$seg"* ]]; then
echo "$line"
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 ))- | sed '/^$/d' \
| while read -r line; do
if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then
continue
fi
if [[ "$line" == *"$seg"* ]]; then
echo "$line"
fi
done
fi
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)
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 'shift-tab:up,tab:down'" ${=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
bindkey '^I' zic-completion