fzf-tab.zsh 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. # temporarily change options
  2. 'builtin' 'local' '-a' '_fzf_tab_opts'
  3. [[ ! -o 'aliases' ]] || _fzf_tab_opts+=('aliases')
  4. [[ ! -o 'sh_glob' ]] || _fzf_tab_opts+=('sh_glob')
  5. [[ ! -o 'no_brace_expand' ]] || _fzf_tab_opts+=('no_brace_expand')
  6. 'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
  7. zmodload zsh/zutil
  8. zmodload -F zsh/stat b:zstat
  9. 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
  10. 0="${${(M)0:#/*}:-$PWD/$0}"
  11. FZF_TAB_HOME=${0:h}
  12. source ${0:h}/lib/zsh-ls-colors/ls-colors.zsh fzf-tab-lscolors
  13. # thanks Valodim/zsh-capture-completion
  14. _fzf_tab_compadd() {
  15. # parse all options
  16. local -A apre hpre dscrs _oad expl
  17. local -a isfile _opts __
  18. zparseopts -E -a _opts P:=apre p:=hpre d:=dscrs X:=expl O:=_oad A:=_oad D:=_oad f=isfile \
  19. i: S: s: I: x: r: R: W: F: M+: E: q e Q n U C \
  20. J:=__ V:=__ a=__ l=__ k=__ o=__ 1=__ 2=__
  21. # just delegate and leave if any of -O, -A or -D are given or fzf-tab is not enabled
  22. zstyle -t ":fzf-tab:${curcontext#:}" ignore
  23. if (( $#_oad != 0 || ! IN_FZF_TAB || ! $? )); then
  24. builtin compadd "$@"
  25. return
  26. fi
  27. # store matches in $__hits and descriptions in $__dscr
  28. local -a __hits __dscr
  29. if (( $#dscrs == 1 )); then
  30. __dscr=( "${(@P)${(v)dscrs}}" )
  31. fi
  32. builtin compadd -A __hits -D __dscr "$@"
  33. local ret=$?
  34. if (( $#__hits == 0 )); then
  35. return $ret
  36. fi
  37. # store $curcontext for furthur usage
  38. _fzf_tab_curcontext=${curcontext#:}
  39. # keep order of group description
  40. [[ -n $expl ]] && _fzf_tab_groups+=$expl
  41. # store these values in _fzf_tab_compcap
  42. local -a keys=(apre hpre isfile PREFIX SUFFIX IPREFIX ISUFFIX)
  43. local key expanded __tmp_value=$'<\0>' # placeholder
  44. for key in $keys; do
  45. expanded=${(P)key}
  46. if [[ $expanded ]]; then
  47. __tmp_value+=$'\0'$key$'\0'$expanded
  48. fi
  49. done
  50. if [[ $expl ]]; then
  51. # store group index
  52. __tmp_value+=$'\0group\0'$_fzf_tab_groups[(ie)$expl]
  53. fi
  54. _opts+=("${(@kv)apre}" "${(@kv)hpre}" $isfile)
  55. __tmp_value+=$'\0args\0'${(pj:\1:)_opts}
  56. # dscr - the string to show to users
  57. # word - the string to be inserted
  58. local dscr word i
  59. for i in {1..$#__hits}; do
  60. word=$__hits[i] dscr=$__dscr[i]
  61. if [[ -n $dscr ]]; then
  62. dscr=${dscr//$'\n'}
  63. elif [[ -n $word ]]; then
  64. dscr=$word
  65. fi
  66. _fzf_tab_compcap+=$dscr$'\2'$__tmp_value${word:+$'\0word\0'$word}
  67. done
  68. # tell zsh that the match is successful
  69. if _fzf_tab_get -t fake-compadd "fakeadd"; then
  70. nm=-1 # see _alternative:76
  71. else
  72. builtin compadd -U -qS '' -R _fzf_tab_remove_space ''
  73. fi
  74. }
  75. # when insert multi results, a whitespace will be added to each result
  76. # remove left space of our fake result because I can't remove right space
  77. # FIXME: what if the left char is not whitespace: `echo $widgets[\t`
  78. _fzf_tab_remove_space() {
  79. [[ $LBUFFER[-1] == ' ' ]] && LBUFFER[-1]=''
  80. }
  81. : ${(A)=FZF_TAB_GROUP_COLORS=\
  82. $'\033[94m' $'\033[32m' $'\033[33m' $'\033[35m' $'\033[31m' $'\033[38;5;27m' $'\033[36m' \
  83. $'\033[38;5;100m' $'\033[38;5;98m' $'\033[91m' $'\033[38;5;80m' $'\033[92m' \
  84. $'\033[38;5;214m' $'\033[38;5;165m' $'\033[38;5;124m' $'\033[38;5;120m'
  85. }
  86. (( $+FZF_TAB_OPTS )) || FZF_TAB_OPTS=(
  87. --ansi # Enable ANSI color support, necessary for showing groups
  88. --expect='$continuous_trigger' # For continuous completion
  89. '--color=hl:$(( $#headers == 0 ? 108 : 255 ))'
  90. --nth=2,3 --delimiter='\x00' # Don't search prefix
  91. --layout=reverse --height='${FZF_TMUX_HEIGHT:=75%}'
  92. --tiebreak=begin -m --bind=tab:down,btab:up,change:top,ctrl-space:toggle --cycle
  93. '--query=$query' # $query will be expanded to query string at runtime.
  94. '--header-lines=$#headers' # $#headers will be expanded to lines of headers at runtime
  95. )
  96. _fzf_tab_get() {
  97. zstyle $1 ":fzf-tab:$_fzf_tab_curcontext" ${@:2}
  98. }
  99. () {
  100. emulate -L zsh -o extended_glob
  101. _fzf_tab_add_default() {
  102. zstyle -t ':fzf-tab:*' $1
  103. (( $? != 2 )) || zstyle ':fzf-tab:*' $1 ${@:2}
  104. }
  105. # Some users may still use variable
  106. _fzf_tab_add_default continuous-trigger ${FZF_TAB_CONTINUOUS_TRIGGER:-'/'}
  107. _fzf_tab_add_default fake-compadd ${FZF_TAB_FAKE_COMPADD:-default}
  108. _fzf_tab_add_default insert-space ${FZF_TAB_INSERT_SPACE:-true}
  109. _fzf_tab_add_default query-string ${(A)=FZF_TAB_QUERY:-prefix input first}
  110. _fzf_tab_add_default single-group ${(A)=FZF_TAB_SINGLE_GROUP:-color header}
  111. _fzf_tab_add_default show-group ${FZF_TAB_SHOW_GROUP:-full}
  112. _fzf_tab_add_default command ${FZF_TAB_COMMAND:-fzf} $FZF_TAB_OPTS
  113. _fzf_tab_add_default extra-opts ''
  114. _fzf_tab_add_default no-group-color ${FZF_TAB_NO_GROUP_COLOR:-$'\033[37m'}
  115. _fzf_tab_add_default group-colors $FZF_TAB_GROUP_COLORS
  116. _fzf_tab_add_default ignore false
  117. if zstyle -m ':completion:*:descriptions' format '*'; then
  118. _fzf_tab_add_default prefix '·'
  119. else
  120. _fzf_tab_add_default prefix ''
  121. fi
  122. unfunction _fzf_tab_add_default
  123. }
  124. # sets `query` to the valid query string
  125. _fzf_tab_find_query_str() {
  126. local key qtype tmp query_string
  127. typeset -g query=
  128. _fzf_tab_get -a query-string query_string
  129. for qtype in $query_string; do
  130. if [[ $qtype == prefix ]]; then
  131. # find the longest common prefix among descriptions
  132. local -a keys=(${_fzf_tab_compcap%$'\2'*})
  133. tmp=$keys[1]
  134. local MATCH match mbegin mend prefix=(${(s::)tmp})
  135. for key in ${keys:1}; do
  136. (( $#tmp )) || break
  137. [[ $key == $tmp* ]] && continue
  138. # interpose characters from the current common prefix and $key and see how
  139. # many pairs of equal characters we get at the start of the resulting string
  140. [[ ${(j::)${${(s::)key[1,$#tmp]}:^prefix}} =~ '^(((.)\3)*)' ]]
  141. # truncate common prefix and maintain loop invariant: ${(s::)tmp} == $prefix
  142. tmp[$#MATCH/2+1,-1]=""
  143. prefix[$#MATCH/2+1,-1]=()
  144. done
  145. elif [[ $qtype == input ]]; then
  146. local fv=${_fzf_tab_compcap[1]#*$'\2'}
  147. local -A v=("${(@0)fv}")
  148. tmp=$v[PREFIX]
  149. if (( $RBUFFER[(i)$v[SUFFIX]] != 1 )); then
  150. tmp=${tmp/%$v[SUFFIX]}
  151. fi
  152. tmp=${${tmp#$v[hpre]}#$v[apre]}
  153. fi
  154. if (( $query_string[(I)longest] )); then
  155. (( $#tmp > $#query )) && query=$tmp
  156. elif [[ -n $tmp ]]; then
  157. query=$tmp && break
  158. fi
  159. done
  160. }
  161. # pupulates array `headers` with group descriptions
  162. _fzf_tab_get_headers() {
  163. typeset -ga headers=()
  164. local i tmp group_colors
  165. local -i mlen=0 len=0
  166. if (( $#_fzf_tab_groups == 1 )) && { ! _fzf_tab_get -m single-group "header" }; then
  167. return
  168. fi
  169. # calculate the max column width
  170. for i in $_fzf_tab_groups; do
  171. (( $#i > mlen )) && mlen=$#i
  172. done
  173. mlen+=1
  174. _fzf_tab_get -a group-colors group_colors
  175. for (( i=1; i<=$#_fzf_tab_groups; i++ )); do
  176. [[ $_fzf_tab_groups[i] == "__hide__"* ]] && continue
  177. if (( len + $#_fzf_tab_groups[i] > COLUMNS - 5 )); then
  178. headers+=$tmp
  179. tmp='' && len=0
  180. fi
  181. if (( len + mlen > COLUMNS - 5 )); then
  182. # the last column doesn't need padding
  183. headers+=$tmp$group_colors[i]$_fzf_tab_groups[i]$'\033[00m'
  184. tmp='' && len=0
  185. else
  186. tmp+=$group_colors[i]${(r:$mlen:)_fzf_tab_groups[i]}$'\033[00m'
  187. len+=$mlen
  188. fi
  189. done
  190. (( $#tmp )) && headers+=$tmp
  191. }
  192. _fzf_tab_colorize() {
  193. emulate -L zsh -o cbases -o octalzeroes
  194. local REPLY
  195. local -a reply stat lstat
  196. # fzf-tab-lscolors::match-by $1 lstat follow
  197. zstat -A lstat -L -- $1
  198. # follow symlink
  199. (( lstat[3] & 0170000 )) && zstat -A stat -- $1 2>/dev/null
  200. fzf-tab-lscolors::from-mode "$1" "$lstat[3]" $stat[3]
  201. # fall back to name
  202. [[ -z $REPLY ]] && fzf-tab-lscolors::from-name $1
  203. # If this is a symlink
  204. if [[ $lstat[14] ]]; then
  205. local sym_color=$REPLY
  206. local rsv_color=$REPLY
  207. local rsv=$lstat[14]
  208. # If this is not a broken symlink
  209. if [[ -e $rsv ]]; then
  210. # fzf-tab-lscolors::match-by $rsv stat
  211. zstat -A stat -- $rsv
  212. fzf-tab-lscolors::from-mode $rsv $stat[3]
  213. # fall back to name
  214. [[ -z $REPLY ]] && fzf-tab-lscolors::from-name $rsv
  215. rsv_color=$REPLY
  216. fi
  217. dpre=$'\033[0m\033['$sym_color'm'
  218. dsuf+=$'\033[0m -> \033['$rsv_color'm'$rsv
  219. else
  220. dpre=$'\033[0m\033['$REPLY'm'
  221. fi
  222. }
  223. # pupulates array `candidates` with completion candidates
  224. _fzf_tab_get_candidates() {
  225. local dsuf dpre k _v filepath first_word show_group no_group_color prefix bs=$'\b'
  226. local -a list_colors group_colors tcandidates reply match mbegin mend
  227. local -i same_word=1 colorful=0
  228. local -Ua duplicate_groups=()
  229. local -A word_map=()
  230. (( $#_fzf_tab_compcap == 0 )) && return
  231. _fzf_tab_get -s show-group show_group
  232. _fzf_tab_get -a group-colors group_colors
  233. _fzf_tab_get -s no-group-color no_group_color
  234. _fzf_tab_get -s prefix prefix
  235. zstyle -a ":completion:$_fzf_tab_curcontext" list-colors list_colors
  236. if (( $+builtins[fzf-tab-colorize] )); then
  237. fzf-tab-colorize -c list_colors
  238. else
  239. local -A namecolors=(${(@s:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
  240. local -A modecolors=(${(@Ms:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
  241. fi
  242. if (( $#_fzf_tab_groups == 1 )); then
  243. _fzf_tab_get -m single-group prefix || prefix=''
  244. _fzf_tab_get -m single-group color || group_colors=($no_group_color)
  245. fi
  246. for k _v in "${(@ps:\2:)_fzf_tab_compcap}"; do
  247. local -A v=("${(@0)_v}")
  248. [[ $v[word] == ${first_word:=$v[word]} ]] || same_word=0
  249. # add character and color to describe the type of the files
  250. dsuf='' dpre=''
  251. if (( $+v[isfile] )); then
  252. filepath=${v[IPREFIX]}${v[hpre]}${k#*$'\b'}
  253. filepath=${(Q)${(e)~filepath}}
  254. if (( $#list_colors && $+builtins[fzf-tab-colorize] )); then
  255. fzf-tab-colorize $filepath 2>/dev/null
  256. dpre=$reply[2]$reply[1] dsuf=$reply[2]$reply[3]
  257. if [[ $reply[4] ]]; then
  258. dsuf+=" -> $reply[4]"
  259. fi
  260. [[ $dpre ]] && colorful=1
  261. else
  262. if [[ -d $filepath ]]; then
  263. dsuf=/
  264. fi
  265. # add color and resolve symlink if have list-colors
  266. # detail: http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fcomplist-Module
  267. if (( $#list_colors )) && [[ -a $filepath || -L $filepath ]]; then
  268. _fzf_tab_colorize $filepath
  269. colorful=1
  270. elif [[ -L $filepath ]]; then
  271. dsuf=@
  272. fi
  273. if [[ $options[list_types] == off ]]; then
  274. dsuf=''
  275. fi
  276. fi
  277. fi
  278. # add color to description if they have group index
  279. if (( $+v[group] )); then
  280. local color=$group_colors[$v[group]]
  281. # add a hidden group index at start of string to keep group order when sorting
  282. # first group index is for builtin sort, sencond is for GNU sort
  283. tcandidates+=$v[group]$'\b'$color$prefix$dpre$'\0'$v[group]$'\b'$k$'\0'$dsuf
  284. else
  285. tcandidates+=$no_group_color$dpre$'\0'$k$'\0'$dsuf
  286. fi
  287. # check group with duplicate member
  288. if [[ $show_group == brief ]]; then
  289. if (( $+word_map[$v[word]] && $+v[group] )); then
  290. duplicate_groups+=$v[group] # add this group
  291. duplicate_groups+=$word_map[$v[word]] # add previous group
  292. fi
  293. word_map[$v[word]]=$v[group]
  294. fi
  295. done
  296. (( same_word )) && tcandidates[2,-1]=()
  297. # sort and remove sort group or other index
  298. zstyle -T ":completion:$_fzf_tab_curcontext" sort
  299. if (( $? != 1 )); then
  300. if (( colorful )); then
  301. # if enable list_colors, we should skip the first field
  302. if [[ ${commands[sort]:A:t} != (|busybox*) ]]; then
  303. # this is faster but doesn't work if `find` is from busybox
  304. tcandidates=(${(f)"$(command sort -u -t '\0' -k 2 <<< ${(pj:\n:)tcandidates})"})
  305. else
  306. # slower but portable
  307. tcandidates=(${(@o)${(@)tcandidates:/(#b)([^$'\0']#)$'\0'(*)/$match[2]$'\0'$match[1]}})
  308. tcandidates=(${(@)tcandidates/(#b)(*)$'\0'([^$'\0']#)/$match[2]$'\0'$match[1]})
  309. fi
  310. else
  311. tcandidates=("${(@o)tcandidates}")
  312. fi
  313. fi
  314. typeset -gUa candidates=("${(@)tcandidates//[0-9]#$bs}")
  315. # hide needless group
  316. if [[ $show_group == brief ]]; then
  317. local i indexs=({1..$#_fzf_tab_groups})
  318. for i in ${indexs:|duplicate_groups}; do
  319. # NOTE: _fzf_tab_groups is unique array
  320. _fzf_tab_groups[i]="__hide__$i"
  321. done
  322. fi
  323. }
  324. _fzf_tab_complete() {
  325. local -a _fzf_tab_compcap
  326. local -Ua _fzf_tab_groups
  327. local choice choices _fzf_tab_curcontext continuous_trigger ignore bs=$'\2'
  328. _fzf_tab__main_complete # must run with user options; don't move `emulate -L zsh` above this line
  329. emulate -L zsh -o extended_glob
  330. # check if we should fall back to zsh builtin completion system
  331. if (( _fzf_tab_ignored )); then
  332. return
  333. fi
  334. _fzf_tab_get -s ignore ignore
  335. if [[ $ignore == <-> ]] && (( $ignore > 1 && $ignore >= $#_fzf_tab_compcap )); then
  336. _fzf_tab_ignored=1
  337. compstate[list]=''
  338. compstate[insert]=''
  339. return
  340. fi
  341. local query candidates=() headers=() command opts
  342. _fzf_tab_get_candidates # sets `candidates`
  343. case $#candidates in
  344. 0) return;;
  345. # NOTE: won't trigger continuous completion
  346. 1) choices=("${_fzf_tab_compcap[1]%$bs*}");;
  347. *)
  348. _fzf_tab_find_query_str # sets `query`
  349. _fzf_tab_get_headers # sets `headers`
  350. _fzf_tab_get -s continuous-trigger continuous_trigger
  351. _fzf_tab_get -a command command
  352. _fzf_tab_get -a extra-opts opts
  353. export CTXT=${${_fzf_tab_compcap[1]#*$'\2'}//$'\0'/$'\2'}
  354. if (( $#headers )); then
  355. choices=$(${(eX)command} $opts <<<${(pj:\n:)headers} <<<${(pj:\n:)candidates})
  356. else
  357. choices=$(${(eX)command} $opts <<<${(pj:\n:)candidates})
  358. fi
  359. choices=(${${${(f)choices}%$'\0'*}#*$'\0'})
  360. unset CTXT
  361. ;;
  362. esac
  363. if [[ $choices[1] && $choices[1] == $continuous_trigger ]]; then
  364. typeset -gi _fzf_tab_continue=1
  365. choices[1]=()
  366. fi
  367. for choice in "$choices[@]"; do
  368. local -A v=("${(@0)${_fzf_tab_compcap[(r)${(b)choice}$bs*]#*$bs}}")
  369. local -a args=("${(@ps:\1:)v[args]}")
  370. [[ -z $args[1] ]] && args=() # don't pass an empty string
  371. IPREFIX=$v[IPREFIX] PREFIX=$v[PREFIX] SUFFIX=$v[SUFFIX] ISUFFIX=$v[ISUFFIX]
  372. builtin compadd "${args[@]:--Q}" -Q -- "$v[word]"
  373. done
  374. compstate[list]=
  375. compstate[insert]=
  376. if (( $#choices == 1 )); then
  377. if _fzf_tab_get -t fake-compadd "fakeadd"; then
  378. compstate[insert]='1'
  379. else
  380. compstate[insert]='2'
  381. fi
  382. _fzf_tab_get -t insert-space
  383. (( $? )) || [[ $RBUFFER == ' '* ]] || compstate[insert]+=' '
  384. elif (( $#choices > 1 )); then
  385. compstate[insert]='all'
  386. fi
  387. }
  388. fzf-tab-complete() {
  389. # this name must be ugly to avoid clashes
  390. local -i _fzf_tab_continue=1 _fzf_tab_ignored=0
  391. while (( _fzf_tab_continue )); do
  392. _fzf_tab_continue=0
  393. local IN_FZF_TAB=1
  394. {
  395. zle .fzf-tab-orig-$_fzf_tab_orig_widget
  396. } always {
  397. IN_FZF_TAB=0
  398. }
  399. if (( _fzf_tab_ignored )); then
  400. zle .fzf-tab-orig-$_fzf_tab_orig_widget
  401. return
  402. fi
  403. if (( _fzf_tab_continue )); then
  404. zle .split-undo
  405. zle .reset-prompt
  406. zle -R
  407. else
  408. zle redisplay
  409. fi
  410. done
  411. }
  412. zle -N fzf-tab-complete
  413. disable-fzf-tab() {
  414. emulate -L zsh -o extended_glob
  415. (( $+_fzf_tab_orig_widget )) || return 0
  416. bindkey '^I' $_fzf_tab_orig_widget
  417. case $_fzf_tab_orig_list_grouped in
  418. 0) zstyle ':completion:*' list-grouped false ;;
  419. 1) zstyle ':completion:*' list-grouped true ;;
  420. 2) zstyle -d ':completion:*' list-grouped ;;
  421. esac
  422. unset _fzf_tab_orig_widget _fzf_tab_orig_list_groupded
  423. # unhook compadd so that _approximate can work properply
  424. unfunction compadd 2>/dev/null
  425. functions[_main_complete]=$functions[_fzf_tab__main_complete]
  426. functions[_approximate]=$functions[_fzf_tab__approximate]
  427. # Don't remove .fzf-tab-orig-$_fzf_tab_orig_widget as we won't be able to reliably
  428. # create it if enable-fzf-tab is called again.
  429. }
  430. enable-fzf-tab() {
  431. emulate -L zsh -o extended_glob
  432. (( ! $+_fzf_tab_orig_widget )) || disable-fzf-tab
  433. typeset -g _fzf_tab_orig_widget="${${$(bindkey '^I')##* }:-expand-or-complete}"
  434. if (( ! $+widgets[.fzf-tab-orig-$_fzf_tab_orig_widget] )); then
  435. # Widgets that get replaced by compinit.
  436. local compinit_widgets=(
  437. complete-word
  438. delete-char-or-list
  439. expand-or-complete
  440. expand-or-complete-prefix
  441. list-choices
  442. menu-complete
  443. menu-expand-or-complete
  444. reverse-menu-complete
  445. )
  446. # Note: We prefix the name of the widget with '.' so that it doesn't get wrapped.
  447. if [[ $widgets[$_fzf_tab_orig_widget] == builtin &&
  448. $compinit_widgets[(Ie)$_fzf_tab_orig_widget] != 0 ]]; then
  449. # We are initializing before compinit and being asked to fall back to a completion
  450. # widget that isn't defined yet. Create our own copy of the widget ahead of time.
  451. zle -C .fzf-tab-orig-$_fzf_tab_orig_widget .$_fzf_tab_orig_widget _main_complete
  452. else
  453. # Copy the widget before it's wrapped by zsh-autosuggestions and zsh-syntax-highlighting.
  454. zle -A $_fzf_tab_orig_widget .fzf-tab-orig-$_fzf_tab_orig_widget
  455. fi
  456. fi
  457. zstyle -t ':completion:*' list-grouped false
  458. typeset -g _fzf_tab_orig_list_grouped=$?
  459. zstyle ':completion:*' list-grouped false
  460. bindkey '^I' fzf-tab-complete
  461. # make sure we can copy them
  462. autoload +X -Uz _main_complete _approximate
  463. # hook compadd
  464. functions[compadd]=$functions[_fzf_tab_compadd]
  465. # hook _main_complete to trigger fzf-tab
  466. functions[_fzf_tab__main_complete]=$functions[_main_complete]
  467. function _main_complete() { _fzf_tab_complete }
  468. # TODO: This is not a full support, see #47
  469. # _approximate will also hook compadd
  470. # let it call _fzf_tab_compadd instead of builtin compadd so that fzf-tab can capture result
  471. # make sure _approximate has been loaded.
  472. functions[_fzf_tab__approximate]=$functions[_approximate]
  473. function _approximate() {
  474. # if not called by fzf-tab, don't do anything with compadd
  475. (( ! IN_FZF_TAB )) || unfunction compadd
  476. _fzf_tab__approximate
  477. (( ! IN_FZF_TAB )) || functions[compadd]=$functions[_fzf_tab_compadd]
  478. }
  479. }
  480. toggle-fzf-tab() {
  481. emulate -L zsh -o extended_glob
  482. if (( $+_fzf_tab_orig_widget )); then
  483. disable-fzf-tab
  484. else
  485. enable-fzf-tab
  486. fi
  487. }
  488. build-fzf-tab-module() {
  489. pushd $FZF_TAB_HOME/modules
  490. CPPFLAGS=-I/usr/local/include CFLAGS="-g -Wall -O3" LDFLAGS=-L/usr/local/lib ./configure --disable-gdbm --without-tcsetpgrp
  491. make -j
  492. popd
  493. }
  494. () {
  495. if [[ -e $FZF_TAB_HOME/modules/Src/aloxaf/fzftab.so ]]; then
  496. module_path+=("$FZF_TAB_HOME/modules/Src")
  497. zmodload aloxaf/fzftab
  498. if [[ $FZF_TAB_MODULE_VERSION != "0.1.1" ]]; then
  499. zmodload -u aloxaf/fzftab
  500. local rebuild
  501. print -Pn "%F{yellow}fzftab module needs to be rebuild, rebuild now?[Y/n]:%f"
  502. read -q rebuild
  503. if [[ $rebuild == y ]]; then
  504. build-fzf-tab-module
  505. zmodload aloxaf/fzftab
  506. fi
  507. fi
  508. fi
  509. }
  510. enable-fzf-tab
  511. zle -N toggle-fzf-tab
  512. # restore options
  513. (( ${#_fzf_tab_opts} )) && setopt ${_fzf_tab_opts[@]}
  514. 'builtin' 'unset' '_fzf_tab_opts'