feat: add plugins for zsh
This commit is contained in:
30
.zsh/zsh-fzf-tab/lib/-ftb-build-module
Normal file
30
.zsh/zsh-fzf-tab/lib/-ftb-build-module
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/hint/zsh
|
||||
emulate -LR zsh -o extended_glob -o err_return
|
||||
|
||||
local zsh_version=${1:-${FZF_TAB_ZSH_SRC_VERSION:-$ZSH_VERSION}}
|
||||
|
||||
# macos check
|
||||
local ret bundle nproc
|
||||
[[ $OSTYPE == darwin* ]] && {
|
||||
[[ -n ${module_path[1]}/**/*.bundle(#qN) ]] && bundle=true
|
||||
nproc=$(sysctl -n hw.logicalcpu)
|
||||
} || {
|
||||
nproc=$(nproc)
|
||||
}
|
||||
|
||||
# clone zsh source code if not exists
|
||||
[[ -d ./zsh/$zsh_version ]] || {
|
||||
git clone --depth=1 --branch zsh-$zsh_version https://github.com/zsh-users/zsh ./zsh/$zsh_version
|
||||
}
|
||||
|
||||
ln -sf $PWD/Src/fzftab.c ./zsh/$zsh_version/Src/Modules/
|
||||
ln -sf $PWD/Src/fzftab.mdd ./zsh/$zsh_version/Src/Modules/
|
||||
|
||||
# build zsh
|
||||
cd -q ./zsh/$zsh_version
|
||||
[[ -f ./configure ]] || ./Util/preconfig
|
||||
[[ -f ./Makefile ]] || ./configure --disable-gdbm --disable-pcre --without-tcsetpgrp --prefix=/tmp/zsh-fzf-tab-module ${bundle:+DL_EXT=bundle}
|
||||
make -j$nproc
|
||||
|
||||
# we only need aloxaf/fzftab.so
|
||||
mv ./Src/Modules/fzftab.(so|bundle) $FZF_TAB_HOME/modules/Src/aloxaf/
|
||||
34
.zsh/zsh-fzf-tab/lib/-ftb-colorize
Normal file
34
.zsh/zsh-fzf-tab/lib/-ftb-colorize
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/hint/zsh
|
||||
emulate -L zsh -o cbases -o octalzeroes
|
||||
|
||||
local REPLY
|
||||
local -a reply stat lstat
|
||||
|
||||
# fzf-tab-lscolors::match-by $1 lstat follow
|
||||
zstat -A lstat -L -- $1
|
||||
# follow symlink
|
||||
(( lstat[3] & 0170000 )) && zstat -A stat -- $1 2>/dev/null
|
||||
|
||||
fzf-tab-lscolors::from-mode "$1" "$lstat[3]" $stat[3]
|
||||
# fall back to name
|
||||
[[ -z $REPLY ]] && fzf-tab-lscolors::from-name $1
|
||||
|
||||
# If this is a symlink
|
||||
if [[ -n $lstat[14] ]]; then
|
||||
local sym_color=$REPLY
|
||||
local rsv_color=$REPLY
|
||||
local rsv=$lstat[14]
|
||||
# If this is not a broken symlink
|
||||
if [[ -e $rsv ]]; then
|
||||
# fzf-tab-lscolors::match-by $rsv stat
|
||||
zstat -A stat -- $rsv
|
||||
fzf-tab-lscolors::from-mode $rsv $stat[3]
|
||||
# fall back to name
|
||||
[[ -z $REPLY ]] && fzf-tab-lscolors::from-name $rsv
|
||||
rsv_color=$REPLY
|
||||
fi
|
||||
dpre=$'\033[0m\033['$sym_color'm'
|
||||
dsuf+=$'\033[0m -> \033['$rsv_color'm'$rsv
|
||||
else
|
||||
dpre=$'\033[0m\033['$REPLY'm'
|
||||
fi
|
||||
109
.zsh/zsh-fzf-tab/lib/-ftb-fzf
Executable file
109
.zsh/zsh-fzf-tab/lib/-ftb-fzf
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/hint/zsh
|
||||
|
||||
# import math functions
|
||||
autoload -Uz zmathfunc
|
||||
zmathfunc
|
||||
|
||||
local tmp_dir=${TMPPREFIX:-/tmp/zsh}-fzf-tab-$USER
|
||||
[[ -d $tmp_dir ]] || command mkdir $tmp_dir
|
||||
|
||||
local ftb_preview_init="
|
||||
zmodload zsh/mapfile
|
||||
local -a _ftb_compcap=(\"\${(@f)mapfile[$tmp_dir/compcap.$$]}\")
|
||||
local -a _ftb_groups=(\"\${(@f)mapfile[$tmp_dir/groups.$$]}\")
|
||||
local bs=\$'\2'
|
||||
# get description
|
||||
export desc=\${\${\"\$(<{f})\"%\$'\0'*}#*\$'\0'}
|
||||
# get ctxt for current completion
|
||||
local -A ctxt=(\"\${(@0)\${_ftb_compcap[(r)\${(b)desc}\$bs*]#*\$bs}}\")
|
||||
# get group
|
||||
if (( \$+ctxt[group] )); then
|
||||
export group=\$_ftb_groups[\$ctxt[group]]
|
||||
fi
|
||||
# get original word
|
||||
export word=\${(Q)ctxt[word]}
|
||||
# get real path if it is file
|
||||
if (( \$+ctxt[realdir] )); then
|
||||
export realpath=\${ctxt[realdir]}\$word
|
||||
fi
|
||||
$(typeset -p words)
|
||||
"
|
||||
local default_binds=tab:down,btab:up,change:top,ctrl-space:toggle,bspace:backward-delete-char/eof,ctrl-h:backward-delete-char/eof
|
||||
local fzf_command fzf_flags fzf_preview debug_command tmp switch_group fzf_pad fzf_min_height binds
|
||||
local ret=0
|
||||
|
||||
-ftb-zstyle -s fzf-command fzf_command || fzf_command=fzf
|
||||
-ftb-zstyle -a fzf-bindings-default tmp && binds=${(j:,:)tmp} || binds=$default_binds
|
||||
-ftb-zstyle -a fzf-bindings tmp && binds+=,${(j:,:)tmp}
|
||||
-ftb-zstyle -a fzf-flags fzf_flags
|
||||
-ftb-zstyle -s fzf-preview fzf_preview
|
||||
-ftb-zstyle -a switch-group switch_group || switch_group=(F1 F2)
|
||||
-ftb-zstyle -s fzf-pad fzf_pad || fzf_pad=2
|
||||
-ftb-zstyle -s fzf-min-height fzf_min_height || fzf_min_height=0
|
||||
|
||||
-ftb-zstyle -a debug-command debug_command && {
|
||||
${(eX)debug_command} $fzf_flags
|
||||
return
|
||||
}
|
||||
|
||||
print -rl -- $_ftb_compcap > $tmp_dir/compcap.$$
|
||||
print -rl -- $_ftb_groups > $tmp_dir/groups.$$
|
||||
print -r -- ${ftb_preview_init/{f}/\$1} > $tmp_dir/ftb_preview_init.$$
|
||||
|
||||
binds=${binds//{_FTB_INIT_}/. $tmp_dir/ftb_preview_init.$$ {f} $'\n'}
|
||||
|
||||
local -i header_lines=$#_ftb_headers
|
||||
local -i lines=$(( $#_ftb_compcap + fzf_pad + header_lines ))
|
||||
local reload_command="$commands[zsh] -f $FZF_TAB_HOME/lib/ftb-switch-group $$ $header_lines $tmp_dir"
|
||||
|
||||
# detect if we will use tmux popup
|
||||
local use_tmux_popup=0
|
||||
if [[ $fzf_command == "ftb-tmux-popup" ]]; then
|
||||
use_tmux_popup=1
|
||||
fi
|
||||
|
||||
if (( ! use_tmux_popup )); then
|
||||
# fzf will cause the current line to refresh, so move the cursor down.
|
||||
echoti cud1 >/dev/tty
|
||||
# reset cursor before call fzf
|
||||
echoti cnorm >/dev/tty 2>/dev/null
|
||||
fi
|
||||
|
||||
cat > $tmp_dir/completions.$$
|
||||
|
||||
local dd='gdd'
|
||||
if (( ${+commands[$dd]} == 0 )) ; then
|
||||
dd='dd'
|
||||
fi
|
||||
if (( ${+commands[$dd]} == 0 )) ; then
|
||||
dd='true' # nop if dd is not installed
|
||||
fi
|
||||
|
||||
_ftb_query="${_ftb_query}$(command "$dd" bs=1G count=1 status=none iflag=nonblock < /dev/tty 2>/dev/null)" || true
|
||||
|
||||
SHELL=$ZSH_NAME $fzf_command \
|
||||
--ansi \
|
||||
--bind=$binds \
|
||||
--bind="${switch_group[1]}:reload($reload_command -1),${switch_group[2]}:reload($reload_command 1)" \
|
||||
--color=hl:$(( header_lines == 0 ? 188 : 255 )) \
|
||||
--cycle \
|
||||
--delimiter='\x00' \
|
||||
--expect=$continuous_trigger,$print_query,$accept_line \
|
||||
--header-lines=$header_lines \
|
||||
--height=${FZF_TMUX_HEIGHT:=$(( min(max(lines, fzf_min_height), LINES / 3 * 2) ))} \
|
||||
--layout=reverse \
|
||||
--multi \
|
||||
--nth=2,3 \
|
||||
--print-query \
|
||||
--query=$_ftb_query \
|
||||
--tiebreak=begin \
|
||||
${fzf_preview:+--preview=${ftb_preview_init/{f}/'{f}'}$fzf_preview} \
|
||||
$fzf_flags < $tmp_dir/completions.$$ || ret=$?
|
||||
|
||||
if (( ! use_tmux_popup )); then
|
||||
echoti civis >/dev/tty 2>/dev/null
|
||||
echoti cuu1 >/dev/tty
|
||||
fi
|
||||
|
||||
command rm $tmp_dir/*.$$ 2>/dev/null
|
||||
return $ret
|
||||
113
.zsh/zsh-fzf-tab/lib/-ftb-generate-complist
Normal file
113
.zsh/zsh-fzf-tab/lib/-ftb-generate-complist
Normal file
@@ -0,0 +1,113 @@
|
||||
#!/hint/zsh
|
||||
|
||||
local dsuf dpre k _v filepath first_word show_group default_color prefix bs=$'\b'
|
||||
local -a list_colors group_colors tcandidates reply match mbegin mend
|
||||
local -i same_word=1 colorful=0
|
||||
local -Ua duplicate_groups=()
|
||||
local -A word_map=()
|
||||
|
||||
(( $#_ftb_compcap == 0 )) && return
|
||||
|
||||
-ftb-zstyle -s show-group show_group || show_group=full
|
||||
-ftb-zstyle -s default-color default_color || default_color=$'\x1b[37m'
|
||||
-ftb-zstyle -s prefix prefix || {
|
||||
zstyle -m ':completion:*:descriptions' format '*' && prefix='·'
|
||||
}
|
||||
-ftb-zstyle -a group-colors group_colors || group_colors=($_ftb_group_colors)
|
||||
zstyle -a ":completion:$_ftb_curcontext" list-colors list_colors
|
||||
|
||||
# init colorize
|
||||
if (( $+builtins[fzf-tab-candidates-generate] )); then
|
||||
fzf-tab-candidates-generate -i list_colors
|
||||
else
|
||||
local -A namecolors=(${(@s:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
|
||||
local -A modecolors=(${(@Ms:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
|
||||
(( $#namecolors == 0 && $#modecolors == 0 )) && list_colors=()
|
||||
fi
|
||||
|
||||
if (( $#_ftb_groups == 1 )); then
|
||||
-ftb-zstyle -m single-group prefix || prefix=''
|
||||
-ftb-zstyle -m single-group color || group_colors=("$default_color")
|
||||
fi
|
||||
|
||||
if (( $+builtins[fzf-tab-candidates-generate] )); then
|
||||
fzf-tab-candidates-generate
|
||||
else
|
||||
for k _v in "${(@ps:\2:)_ftb_compcap}"; do
|
||||
local -A v=("${(@0)_v}")
|
||||
[[ $v[word] == ${first_word:=$v[word]} ]] || same_word=0
|
||||
|
||||
# add character and color to describe the type of the files
|
||||
dsuf='' dpre=''
|
||||
if (( $+v[realdir] )); then
|
||||
filepath=$v[realdir]${(Q)v[word]}
|
||||
if [[ -d $filepath ]]; then
|
||||
dsuf=/
|
||||
fi
|
||||
# add color and resolve symlink if have list-colors
|
||||
# detail: http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fcomplist-Module
|
||||
if (( $#list_colors )) && [[ -a $filepath || -L $filepath ]]; then
|
||||
-ftb-colorize $filepath
|
||||
colorful=1
|
||||
elif [[ -L $filepath ]]; then
|
||||
dsuf=@
|
||||
fi
|
||||
if [[ $options[list_types] == off ]]; then
|
||||
dsuf=''
|
||||
fi
|
||||
fi
|
||||
|
||||
# add color to description if they have group index
|
||||
if (( $+v[group] )); then
|
||||
local color=$group_colors[$v[group]]
|
||||
# add a hidden group index at start of string to keep group order when sorting
|
||||
# first group index is for builtin sort, sencond is for GNU sort
|
||||
tcandidates+=$v[group]$'\b'$color$prefix$dpre$'\0'$v[group]$'\b'$k$'\0'$dsuf
|
||||
else
|
||||
tcandidates+=$default_color$dpre$'\0'$k$'\0'$dsuf
|
||||
fi
|
||||
|
||||
# check group with duplicate member
|
||||
if [[ $show_group == brief ]]; then
|
||||
if (( $+word_map[$v[word]] && $+v[group] )); then
|
||||
duplicate_groups+=$v[group] # add this group
|
||||
duplicate_groups+=$word_map[$v[word]] # add previous group
|
||||
fi
|
||||
word_map[$v[word]]=$v[group]
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
(( same_word )) && tcandidates[2,-1]=()
|
||||
|
||||
# sort and remove sort group or other index
|
||||
zstyle -T ":completion:$_ftb_curcontext" sort
|
||||
if (( $? != 1 )); then
|
||||
if (( colorful )); then
|
||||
# if enable list_colors, we should skip the first field
|
||||
if [[ ${commands[sort]:A:t} != (|busybox*) ]]; then
|
||||
# this is faster but doesn't work if `find` is from busybox
|
||||
tcandidates=(${(f)"$(command sort -u -t '\0' -k 2 <<< ${(pj:\n:)tcandidates})"})
|
||||
else
|
||||
# slower but portable
|
||||
tcandidates=(${(@o)${(@)tcandidates:/(#b)([^$'\0']#)$'\0'(*)/$match[2]$'\0'$match[1]}})
|
||||
tcandidates=(${(@)tcandidates/(#b)(*)$'\0'([^$'\0']#)/$match[2]$'\0'$match[1]})
|
||||
fi
|
||||
else
|
||||
tcandidates=("${(@o)tcandidates}")
|
||||
fi
|
||||
fi
|
||||
typeset -gUa _ftb_complist=("${(@)tcandidates//[0-9]#$bs}")
|
||||
|
||||
# hide needless group
|
||||
if (( $#_ftb_groups )); then
|
||||
local i to_hide indexs=({1..$#_ftb_groups})
|
||||
case $show_group in
|
||||
brief) to_hide=(${indexs:|duplicate_groups}) ;;
|
||||
none) to_hide=($indexs) ;;
|
||||
esac
|
||||
for i in $to_hide; do
|
||||
# NOTE: _ftb_groups is unique array
|
||||
_ftb_groups[i]="__hide__$i"
|
||||
done
|
||||
fi
|
||||
35
.zsh/zsh-fzf-tab/lib/-ftb-generate-header
Normal file
35
.zsh/zsh-fzf-tab/lib/-ftb-generate-header
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/hint/zsh
|
||||
|
||||
typeset -ga _ftb_headers=()
|
||||
local i tmp group_colors
|
||||
local -i mlen=0 len=0
|
||||
|
||||
if (( $#_ftb_groups == 1 )) && { ! -ftb-zstyle -m single-group "header" }; then
|
||||
return
|
||||
fi
|
||||
|
||||
# calculate the max column width
|
||||
for i in $_ftb_groups; do
|
||||
(( $#i > mlen )) && mlen=$#i
|
||||
done
|
||||
mlen+=1
|
||||
|
||||
-ftb-zstyle -a group-colors group_colors || group_colors=($_ftb_group_colors)
|
||||
|
||||
for (( i=1; i<=$#_ftb_groups; i++ )); do
|
||||
[[ $_ftb_groups[i] == "__hide__"* ]] && continue
|
||||
|
||||
if (( len + $#_ftb_groups[i] > COLUMNS - 5 )); then
|
||||
_ftb_headers+=$tmp
|
||||
tmp='' && len=0
|
||||
fi
|
||||
if (( len + mlen > COLUMNS - 5 )); then
|
||||
# the last column doesn't need padding
|
||||
_ftb_headers+=$tmp$group_colors[i]$_ftb_groups[i]$'\033[00m'
|
||||
tmp='' && len=0
|
||||
else
|
||||
tmp+=$group_colors[i]${(r:$mlen:)_ftb_groups[i]}$'\033[00m'
|
||||
len+=$mlen
|
||||
fi
|
||||
done
|
||||
(( $#tmp )) && _ftb_headers+=$tmp
|
||||
40
.zsh/zsh-fzf-tab/lib/-ftb-generate-query
Normal file
40
.zsh/zsh-fzf-tab/lib/-ftb-generate-query
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/hint/zsh
|
||||
|
||||
if zmodload -s zsh/pcre; then
|
||||
setopt localoptions rematch_pcre
|
||||
fi
|
||||
|
||||
local key qtype tmp query_string
|
||||
typeset -g _ftb_query=
|
||||
-ftb-zstyle -a query-string query_string || query_string=(prefix input first)
|
||||
for qtype in $query_string; do
|
||||
if [[ $qtype == prefix ]]; then
|
||||
# find the longest common prefix among descriptions
|
||||
local -a keys=(${_ftb_compcap%$'\2'*})
|
||||
tmp=$keys[1]
|
||||
local MATCH match mbegin mend prefix=(${(s::)tmp})
|
||||
for key in ${keys:1}; do
|
||||
(( $#tmp )) || break
|
||||
[[ $key == $tmp* ]] && continue
|
||||
# interpose characters from the current common prefix and $key and see how
|
||||
# many pairs of equal characters we get at the start of the resulting string
|
||||
[[ ${(j::)${${(s::)key[1,$#tmp]}:^prefix}} =~ '^(((.)\3)*)' ]]
|
||||
# truncate common prefix and maintain loop invariant: ${(s::)tmp} == $prefix
|
||||
tmp[$#MATCH/2+1,-1]=""
|
||||
prefix[$#MATCH/2+1,-1]=()
|
||||
done
|
||||
elif [[ $qtype == input ]]; then
|
||||
local fv=${_ftb_compcap[1]#*$'\2'}
|
||||
local -A v=("${(@0)fv}")
|
||||
tmp=$v[PREFIX]
|
||||
if (( $RBUFFER[(i)$v[SUFFIX]] != 1 )); then
|
||||
tmp=${tmp/%$v[SUFFIX]}
|
||||
fi
|
||||
tmp=${${tmp#$v[hpre]}#$v[apre]}
|
||||
fi
|
||||
if (( $query_string[(I)longest] )); then
|
||||
(( $#tmp > $#_ftb_query )) && _ftb_query=$tmp
|
||||
elif [[ -n $tmp ]]; then
|
||||
_ftb_query=$tmp && break
|
||||
fi
|
||||
done
|
||||
10
.zsh/zsh-fzf-tab/lib/-ftb-version
Normal file
10
.zsh/zsh-fzf-tab/lib/-ftb-version
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/hint/zsh
|
||||
emulate -L zsh -o pipe_fail
|
||||
pushd -q $FZF_TAB_HOME
|
||||
if [[ -d .git ]]; then
|
||||
git describe --long --tags --abbrev=7 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' \
|
||||
|| printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
|
||||
else
|
||||
echo unknown
|
||||
fi
|
||||
popd -q
|
||||
38
.zsh/zsh-fzf-tab/lib/ftb-switch-group
Normal file
38
.zsh/zsh-fzf-tab/lib/ftb-switch-group
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/hint/zsh
|
||||
emulate -L zsh -o extended_glob
|
||||
|
||||
zmodload zsh/mapfile
|
||||
|
||||
# receive arguments
|
||||
local pid=$1 header_lines=$2 tmp_dir=$3 offset=$@[-1]
|
||||
|
||||
# read completion list
|
||||
local -a list=(${(f)mapfile[$tmp_dir/completions.$pid]})
|
||||
|
||||
# get total group count
|
||||
if (( $#list > 10000 )); then
|
||||
local -Ua total=(${(f)"$(print -l ${list:$header_lines} | grep -a -oP '^\x1b\[[0-9;]*m')"})
|
||||
else
|
||||
local -Ua total=(${(M)${list:$header_lines}#$'\x1b['[0-9;]#*m})
|
||||
fi
|
||||
|
||||
# get current group index, start from 2
|
||||
local current=2
|
||||
if [[ -f $tmp_dir/current-group.$pid ]]; then
|
||||
current=$(( $(<$tmp_dir/current-group.$pid) + offset ))
|
||||
fi
|
||||
(( current > $#total )) && current=1
|
||||
(( current == 0 )) && current=$#total
|
||||
echo $current > $tmp_dir/current-group.$pid
|
||||
|
||||
# print headers
|
||||
if (( header_lines != 0 )); then
|
||||
print -l ${list[1,header_lines]/${total[current]}/$'\x1b[1m'}
|
||||
fi
|
||||
|
||||
# print current group
|
||||
if (( $#list > 10000 )); then
|
||||
print -l ${list:$header_lines} | grep -a -F "${total[current]}"
|
||||
else
|
||||
print -l ${(M)${list:$header_lines}:#${total[current]}*}
|
||||
fi
|
||||
100
.zsh/zsh-fzf-tab/lib/ftb-tmux-popup
Executable file
100
.zsh/zsh-fzf-tab/lib/ftb-tmux-popup
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/hint/zsh
|
||||
# Show results with tmux popup
|
||||
# Example usage:
|
||||
# zstyle ':fzf-tab:*' fzf-command ftb-tmux-popup
|
||||
# zstyle ':fzf-tab:*' popup-pad 0 0
|
||||
# It can also be used as a standalone tool, like:
|
||||
# ls | ftb-tmux-popup
|
||||
emulate -L zsh -o extended_glob
|
||||
|
||||
# import math functions (only if they're not already defined)
|
||||
if (( ! $+functions[zsh_math_func_min] )); then
|
||||
autoload -Uz zmathfunc
|
||||
zmathfunc
|
||||
fi
|
||||
|
||||
: ${tmp_dir:=${TMPPREFIX:-/tmp/zsh}-fzf-tab-$USER}
|
||||
|
||||
# fallback to fzf if it is not running in tmux
|
||||
if (( ! $+TMUX_PANE )); then
|
||||
fzf $@
|
||||
return
|
||||
fi
|
||||
|
||||
local ret=0
|
||||
|
||||
local -a fzf_opts=($@)
|
||||
fzf_opts=(${${fzf_opts/--height*}/--layout*})
|
||||
|
||||
# get position of cursor and size of window
|
||||
local -a tmp=($(command tmux display-message -p "#{pane_top} #{cursor_y} #{pane_left} #{cursor_x} #{window_height} #{window_width} #{status} #{status-position}"))
|
||||
local cursor_y=$((tmp[1] + tmp[2])) cursor_x=$((tmp[3] + tmp[4])) window_height=$tmp[5] window_width=$tmp[6] window_top=0
|
||||
|
||||
if [[ $tmp[8] == 'top' ]]; then
|
||||
window_top=$tmp[7]
|
||||
cursor_y=$((cursor_y + window_top))
|
||||
fi
|
||||
|
||||
# if not called by fzf-tab
|
||||
if (( ! $+IN_FZF_TAB )); then
|
||||
[[ -d $tmp_dir ]] || mkdir -p $tmp_dir
|
||||
cat > $tmp_dir/completions.$$
|
||||
fi
|
||||
|
||||
local text REPLY comp_lines comp_length length popup_pad popup_min_size
|
||||
|
||||
zstyle -a ":fzf-tab:$_ftb_curcontext" popup-pad popup_pad || popup_pad=(0 0)
|
||||
zstyle -a ":fzf-tab:$_ftb_curcontext" popup-min-size popup_min_size || popup_min_size=(0 0)
|
||||
|
||||
# get the size of content, note we should remove all ANSI color code
|
||||
comp_lines=$(( ${#${(f)mapfile[$tmp_dir/completions.$$]}} + $popup_pad[2] ))
|
||||
if (( comp_lines <= 500 )); then
|
||||
comp_length=0
|
||||
for line in ${(f)mapfile[$tmp_dir/completions.$$]}; do
|
||||
length=${(m)#${(S)line//$'\x1b['[0-9]#*m}}
|
||||
(( length >= comp_length )) && comp_length=$length
|
||||
done
|
||||
else
|
||||
# FIXME: can't get the correct width of CJK characters.
|
||||
comp_length=$( command perl -ne 's/\x1b\[[0-9;]*m//g;s/\x00//g; $m= length() if $m < length(); END { print $m }' < $tmp_dir/completions.$$ )
|
||||
fi
|
||||
comp_length=$(( comp_length + $popup_pad[1] ))
|
||||
|
||||
local popup_height popup_y popup_width popup_x adjust_height
|
||||
|
||||
# adjust the popup height if the fzf finder info style is not default
|
||||
if (( $fzf_opts[(I)--info=*(hidden|inline)*] > 0 )); then
|
||||
adjust_height=-1
|
||||
fi
|
||||
|
||||
# calculate the popup height and y position
|
||||
if (( cursor_y * 2 > window_height )); then
|
||||
# show above the cursor
|
||||
popup_height=$(( min(max(comp_lines + 4, popup_min_size[2]), cursor_y - window_top) + adjust_height ))
|
||||
popup_y=$cursor_y
|
||||
if zstyle -T ":fzf-tab:$_ftb_curcontext" popup-smart-tab; then
|
||||
fzf_opts+=(--bind=tab:up,btab:down)
|
||||
fi
|
||||
fzf_opts+=(--layout=default)
|
||||
else
|
||||
# show below the cursor
|
||||
popup_height=$(( min(max(comp_lines + 4, popup_min_size[2]), window_height - cursor_y + window_top - 1) + adjust_height ))
|
||||
popup_y=$(( cursor_y + popup_height + 1 ))
|
||||
fzf_opts+=(--layout=reverse)
|
||||
fi
|
||||
|
||||
# calculate the popup width and x position
|
||||
popup_width=$(( min(max(comp_length + 5, popup_min_size[1]), window_width) ))
|
||||
popup_x=$(( cursor_x + popup_width > window_width ? window_width - popup_width : cursor_x ))
|
||||
|
||||
echo -E "env SHELL=$ZSH_NAME $commands[fzf] ${(qq)fzf_opts[@]} < $tmp_dir/completions.$$ > $tmp_dir/result-$$" > $tmp_dir/fzf-$$
|
||||
{
|
||||
tmux popup -x $popup_x -y $popup_y \
|
||||
-w $popup_width -h $popup_height \
|
||||
-d $PWD -E ". $tmp_dir/fzf-$$" || ret=$?
|
||||
echo -E "$(<$tmp_dir/result-$$)"
|
||||
} always {
|
||||
command rm $tmp_dir/*-$$
|
||||
(( $+IN_FZF_TAB )) || command rm $tmp_dir/completions.$$
|
||||
}
|
||||
return $ret
|
||||
21
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/LICENSE
Normal file
21
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Gamma
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
114
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/README.md
Normal file
114
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/README.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# zsh-ls-colors
|
||||
|
||||

|
||||
|
||||
A zsh library to use `LS_COLORS` in scripts or other plugins.
|
||||
|
||||
For a simple demo, see the `demo` script in this repo.
|
||||
|
||||
For more advanced usage,
|
||||
instructions are located at top of the source files for `from-mode` and `from-name`.
|
||||
If a use case isn't adequately covered,
|
||||
please open an issue!
|
||||
|
||||
## Using zsh-ls-colors in a plugin
|
||||
|
||||
You can use this as a submodule or a subtree.
|
||||
|
||||
### submodule:
|
||||
|
||||
```sh
|
||||
# Add (only once)
|
||||
git submodule add git://github.com/xPMo/zsh-ls-colors.git ls-colors
|
||||
git commit -m 'Add ls-colors as submodule'
|
||||
|
||||
# Update
|
||||
cd ls-colors
|
||||
git fetch
|
||||
git checkout origin/master
|
||||
cd ..
|
||||
git commit ls-colors -m 'Update ls-colors to latest'
|
||||
```
|
||||
|
||||
### Subtree:
|
||||
|
||||
```sh
|
||||
# Initial add
|
||||
git subtree add --prefix=ls-colors/ --squash -m 'Add ls-colors as a subtree' \
|
||||
git://github.com/xPMo/zsh-ls-colors.git master
|
||||
|
||||
# Update
|
||||
git subtree pull --prefix=ls-colors/ --squash -m 'Update ls-colors to latest' \
|
||||
git://github.com/xPMo/zsh-ls-colors.git master
|
||||
|
||||
|
||||
# Or, after adding a remote:
|
||||
git remote add ls-colors git://github.com/xPMo/zsh-ls-colors.git
|
||||
|
||||
# Initial add
|
||||
git subtree add --prefix=ls-colors/ --squash -m 'Add ls-colors as a subtree' ls-colors master
|
||||
|
||||
# Update
|
||||
git subtree pull --prefix=ls-colors/ --squash -m 'Update ls-colors to latest' ls-colors master
|
||||
```
|
||||
|
||||
### Function namespacing
|
||||
|
||||
Since functions are a public namespace,
|
||||
this plugin allows you to customize the preifix for your plugin:
|
||||
|
||||
```zsh
|
||||
# load functions as my-lscolors::{init,match-by,from-name,from-mode}
|
||||
source ${0:h}/ls-colors/ls-colors.zsh my-lscolors
|
||||
```
|
||||
|
||||
### Parameter namespacing
|
||||
|
||||
While indirect parameter expansion exists with `${(P)var}`,
|
||||
it doesn't play nicely with array parameters.
|
||||
|
||||
There are multiple strategies to prevent unnecessary re-parsing:
|
||||
|
||||
```zsh
|
||||
# Call once when loading.
|
||||
# Pollutes global namespace but prevents re-parsing
|
||||
ls-color::init
|
||||
```
|
||||
|
||||
```zsh
|
||||
# Don't call init at all and only use ::match-by.
|
||||
# Doesn't pollute global namespace but reparses LS_COLORS on every call
|
||||
ls-color::match-by $file lstat
|
||||
```
|
||||
|
||||
```zsh
|
||||
# Initialize within a scope with local parameters.
|
||||
# Best for not polluting global namespace when multiple filenames need to be parsed.
|
||||
(){
|
||||
local -A namecolors modecolors
|
||||
ls-color::init
|
||||
|
||||
for arg; do
|
||||
...
|
||||
done
|
||||
}
|
||||
```
|
||||
|
||||
```zsh
|
||||
# Serialize:
|
||||
typeset -g LS_COLORS_CACHE_FILE=$(mktemp)
|
||||
(){
|
||||
local -A namecolors modecolors
|
||||
ls-color::init
|
||||
typeset -p modecolors namecolors >| $LS_COLORS_CACHE_FILE
|
||||
zcompile $LS_COLORS_CACHE_FILE
|
||||
}
|
||||
|
||||
my-function(){
|
||||
local -A namecolors modecolors
|
||||
source $LS_COLORS_CACHE_FILE
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
65
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/demo
Executable file
65
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/demo
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env zsh
|
||||
# set $0 (ref: zdharma.org/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html#zero-handling)
|
||||
0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
|
||||
0="${${(M)0:#/*}:-$PWD/$0}"
|
||||
|
||||
# load library functions
|
||||
source ls-colors.zsh ''
|
||||
|
||||
# to name the functions with a different namespace
|
||||
# call source with a different argument
|
||||
#source my-plugin::ls
|
||||
|
||||
# init (sets modecolors and namecolors)
|
||||
# You have options. Either you can pollute global namespace:
|
||||
ls-color::init
|
||||
# Or you can have ::match-by re-parse colors on every call
|
||||
: # (do nothing)
|
||||
# Or if you have multiple calls, you can parse colors once for a scope:
|
||||
(){
|
||||
local -A modecolors namecolors
|
||||
ls-color::init
|
||||
|
||||
for arg; do
|
||||
ls-color::match-by $arg lstat
|
||||
: do something else
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# colors can also be added for other globs after init as well:
|
||||
namecolors[*.md]='01' # bold markdown files
|
||||
|
||||
# EXTENDED_GLOB is enabled when matching, so things like this are possible:
|
||||
namecolors[(#i)(*/|)license(|.*)]='04' # underline LICENSE, or license.txt, or similar
|
||||
|
||||
local file reply
|
||||
# color each file in the argument list
|
||||
for file; do
|
||||
ls-color::match-by $file all
|
||||
# point to symlink resolution if it exists
|
||||
print '\e['$reply[1]'m'$file'\e[0m'${reply[2]:+' → \e['$reply[3]'m'$reply[2]'\e[0m'}
|
||||
done
|
||||
|
||||
# =======================
|
||||
# Alternate manual method:
|
||||
for file; do
|
||||
ls-color::match-by $file lstat follow
|
||||
if [[ $reply[2] ]]; then
|
||||
# This is a symlink
|
||||
symlink_color=$reply[1]
|
||||
# If broken, use link color for destination
|
||||
resolved_color=$reply[1]
|
||||
resolved=$reply[2]
|
||||
if [[ -e $file ]]; then
|
||||
# Not broken, update destination color
|
||||
ls-color::match-by $file stat
|
||||
resolved_color=$reply[1]
|
||||
fi
|
||||
print '\e['$symlink_color'm'$file'\e[0m → \e['$resolved_color'm'$resolved'\e[0m'
|
||||
else
|
||||
# This is not a symlink
|
||||
print '\e['$reply[1]'m'$file'\e[0m'
|
||||
fi
|
||||
done
|
||||
|
||||
186
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/ls-colors.zsh
Normal file
186
.zsh/zsh-fzf-tab/lib/zsh-ls-colors/ls-colors.zsh
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
# set the prefix for all functions
|
||||
local pfx=${1:-'ls-color'}
|
||||
|
||||
# {{{ From mode
|
||||
# Usage:
|
||||
# $1: filename
|
||||
# $2: The value of struct stat st_mode
|
||||
# If empty, modecolors lookup will be skipped
|
||||
# $3: (If symlink) The value of struct stat st_mode
|
||||
# for the target of $1's symlink. If unset,
|
||||
# interpret as a broken link.
|
||||
# Sets REPLY to the console code
|
||||
${pfx}::from-mode () {
|
||||
|
||||
emulate -L zsh
|
||||
setopt cbases octalzeroes extendedglob
|
||||
|
||||
[[ -z $2 ]] && return 1
|
||||
|
||||
local -i reg=0
|
||||
local -a codes
|
||||
|
||||
local -i st_mode=$(($2))
|
||||
# See man 7 inode for more info
|
||||
# file type
|
||||
case $(( st_mode & 0170000 )) in
|
||||
$(( 0140000 )) ) codes=( $modecolors[so] ) ;;
|
||||
$(( 0120000 )) ) # symlink, special handling
|
||||
if ! (($+3)); then
|
||||
REPLY=$modecolors[or]
|
||||
elif [[ $modecolors[ln] = target ]]; then
|
||||
"$0" "$1" "${@:3}"
|
||||
else
|
||||
REPLY=$modecolors[ln]
|
||||
fi
|
||||
return
|
||||
;;
|
||||
$(( 0100000 )) ) codes=( ); reg=1 ;; # regular file
|
||||
$(( 0060000 )) ) codes=( $modecolors[bd] ) ;;
|
||||
$(( 0040000 )) ) codes=( $modecolors[di] ) ;;
|
||||
$(( 0020000 )) ) codes=( $modecolors[cd] ) ;;
|
||||
$(( 0010000 )) ) codes=( $modecolors[pi] ) ;;
|
||||
esac
|
||||
|
||||
# setuid/setgid/sticky/other-writable
|
||||
(( st_mode & 04000 )) && codes+=( $modecolors[su] )
|
||||
(( st_mode & 02000 )) && codes+=( $modecolors[sg] )
|
||||
(( ! reg )) && case $(( st_mode & 01002 )) in
|
||||
# sticky
|
||||
$(( 01000 )) ) codes+=( $modecolors[st] ) ;;
|
||||
# other-writable
|
||||
$(( 00002 )) ) codes+=( $modecolors[ow] ) ;;
|
||||
# other-writable and sticky
|
||||
$(( 01002 )) ) codes+=( $modecolors[tw] ) ;;
|
||||
esac
|
||||
|
||||
# executable
|
||||
if (( ! $#codes )); then
|
||||
(( st_mode & 0111 )) && codes+=( $modecolors[ex] )
|
||||
fi
|
||||
|
||||
# return nonzero if no matching code
|
||||
[[ ${REPLY::=${(j:;:)codes}} ]]
|
||||
} # }}}
|
||||
# {{{ From name
|
||||
# Usage:
|
||||
# $1: filename
|
||||
#
|
||||
# Sets REPLY to the console code
|
||||
${pfx}::from-name () {
|
||||
|
||||
emulate -L zsh
|
||||
setopt extendedglob
|
||||
|
||||
# Return non-zero if no keys match
|
||||
[[ ${REPLY::=$namecolors[(k)$1]} ]]
|
||||
} # }}}
|
||||
# {{{ Init
|
||||
# WARNING: initializes namecolors and modecolors in global scope
|
||||
${pfx}::init () {
|
||||
emulate -L zsh
|
||||
|
||||
# Use $1 if provided, otherwise use LS_COLORS
|
||||
# Use LSCOLORS on BSD
|
||||
local LS_COLORS=${1:-${LS_COLORS:-$LSCOLORS}}
|
||||
|
||||
# read in LS_COLORS
|
||||
typeset -gA namecolors=(${(@s:=:)${(@s.:.)LS_COLORS}:#[[:alpha:]][[:alpha:]]=*})
|
||||
typeset -gA modecolors=(${(@Ms:=:)${(@s.:.)LS_COLORS}:#[[:alpha:]][[:alpha:]]=*})
|
||||
}
|
||||
# }}}
|
||||
# {{{ Match by
|
||||
# Usage:
|
||||
# $1: filename
|
||||
# Optional (must be $2): g[lobal]: Use existing stat | lstat in parent scope
|
||||
# ${@:2}: Append to reply:
|
||||
# - l[stat] : Look up using lstat (don't follow symlink), if empty match name
|
||||
# - s[tat] : Look up using stat (do follow symlink), if empty match name
|
||||
# - n[ame] : Only match name
|
||||
# - f[ollow]: Get resolution path of symlink
|
||||
# - L[stat] : Same as above but don't match name
|
||||
# - S[tat] : Same as above but don't match name
|
||||
# - a[ll] : If a broken symlink: lstat follow lstat
|
||||
# : If a symlink : lstat follow stat
|
||||
# : Otherwise : lstat
|
||||
# - A[ll] : If a broken symlink: Lstat follow Lstat
|
||||
# : If a symlink : Lstat follow Stat
|
||||
# : Otherwise : Lstat
|
||||
#
|
||||
# or returns non-zero
|
||||
${pfx}::match-by () {
|
||||
emulate -L zsh
|
||||
setopt extendedglob cbases octalzeroes
|
||||
|
||||
local arg REPLY name=$1 pfx=${0%::match-by}
|
||||
shift
|
||||
|
||||
# init in local scope if not using global params
|
||||
if ! [[ -v namecolors && -v modecolors ]]; then
|
||||
local -A namecolors modecolors
|
||||
${pfx}::init
|
||||
fi
|
||||
|
||||
if [[ ${1:l} = (g|global) ]]; then
|
||||
shift
|
||||
else
|
||||
local -a stat lstat
|
||||
declare -ga reply=()
|
||||
fi
|
||||
|
||||
zmodload -F zsh/stat b:zstat
|
||||
for arg; do
|
||||
case ${arg[1]:l} in
|
||||
n|name)
|
||||
${pfx}::from-name $name
|
||||
reply+=("$REPLY")
|
||||
;;
|
||||
l|lstat)
|
||||
(($#lstat)) || zstat -A lstat -L $name || return 1
|
||||
if ((lstat[3] & 0170000 )); then
|
||||
# follow symlink
|
||||
(($#stat)) || zstat -A stat $name 2>/dev/null
|
||||
fi
|
||||
${pfx}::from-mode "$name" "$lstat[3]" $stat[3]
|
||||
if [[ $REPLY || ${2[1]} = L ]]; then
|
||||
reply+=("$REPLY")
|
||||
else # fall back to name
|
||||
"$0" "$name" g n
|
||||
fi
|
||||
;;
|
||||
s|stat)
|
||||
(($#stat)) || zstat -A stat $name || return 1
|
||||
${pfx}::from-mode $name $stat[3]
|
||||
reply+=("$REPLY")
|
||||
if [[ $REPLY || ${arg[1]} = S ]]; then
|
||||
reply+=("$REPLY")
|
||||
else # fall back to name
|
||||
"$0" "$name" g n
|
||||
fi
|
||||
;;
|
||||
f|follow)
|
||||
(($#lstat)) || zstat -A lstat -L $name || return 1
|
||||
reply+=("$lstat[14]")
|
||||
;;
|
||||
a|all)
|
||||
# Match case
|
||||
"$0" "$name" g ${${${arg[1]%a}:+L}:-l}
|
||||
# won't append if empty
|
||||
reply+=($lstat[14])
|
||||
# $stat[14] will be empty if not a symlink
|
||||
if [[ $lstat[14] ]]; then
|
||||
if [[ -e $name ]]; then
|
||||
"$0" "$name" g ${${${arg[1]%a}:+S}:-s}
|
||||
else
|
||||
reply+=($reply[-2])
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*) return 2 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
# }}}
|
||||
# vim: set foldmethod=marker:
|
||||
Reference in New Issue
Block a user