Skip to content

Commit

Permalink
Introducing cycling and ice-completion (<Alt>-i).
Browse files Browse the repository at this point in the history
Cycling will allow to choose a particular match, say for, e.g.:
zinit at<Alt-i>   »   zinit atclone<Alt-i> » zinit atinit<Alt-i> »
                  »   zinit atload<Alt-i> » zinit atpull<Alt-i> »
                  »   zinit run-atpull<Alt-i> » zinit atclone"

It works for plugin-id completion in the same way, i.e.: <Alt-a>
cycles through the matches.

For ices, the value of the ice is preserved, e.g.:
zinit at'./configure'<Alt-i> » zinit atclone'./configure'<Alt-i> »
                             » zinit atinit'./configure'<Alt-i> »
                             » etc.
  • Loading branch information
psprint committed Jul 6, 2022
1 parent 7363ebb commit 18a03d2
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 15 deletions.
59 changes: 53 additions & 6 deletions ziactioncomplete
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,64 @@ ziactioncomplete()
emulate -L zsh -o extended_glob -o warn_create_global -o typeset_silent \
-o no_short_loops -o rc_quotes -o no_auto_pushd

# The index of the match that's inserted in cmd line
integer -g ziac_midx
typeset -ga ziac_matches ziac_wids
typeset -g ziac_prevw ziac_mt
local -a match mbegin mend

#
# Invoke the helper/worker function that does all needed $BUFFER processing
ziprocessbuffer
#

ziprocessbuffer || return 1
integer i j pos=$CURSOR size=${#ZINIT_PB_WORDS} newcursor
local w=$ZINIT_PB_WORDS[ZINIT_PB_SELECTED_WORD] buf
local -a matches=( $ZINIT[PLUGINS_DIR]/*${w//\//---}*(-onND[1,8]) )
REPLY=${${matches[1]:t}//---//}
local w=$ZINIT_PB_WORDS[ZINIT_PB_SELECTED_WORD] LWIDGET buf

#
# Handle LASTWIDGET issues particularly with zsh-autosuggestions
# It leaks name of its hook into this variable causing much distress
#

if [[ $LASTWIDGET == autosuggest-suggest ]]; then
LWIDGET=${ziac_wids[-1]:-$WIDGET}
else
ziac_wids+=( $WIDGET )
LWIDGET=$LASTWIDGET
fi

if [[ $WIDGET == ziactioncompleteice && $WIDGET != $LWIDGET && $ziac_prevw != $w ]]
then
local -a ice_order=(
${(Aons:|:)ZINIT[ice-list]}
${(@)${(A@kons:|:)${ZINIT_EXTS[ice-mods]//\'\'/}}/(#s)<->-/}
)
ziac_prevw=$w
match=()
w=${w//(#b)(([=:]|)[\'\"]?#([\'\"]|(#e)))/}
ziac_mt=$match[1]

ziac_matches=( ${(onM)ice_order:#*$w*} )
elif (( ziac_midx )) && [[ $WIDGET == ziac*ice && $WIDGET == $LWIDGET ]]; then
ziac_midx+=1
fi
if [[ $WIDGET == ziactioncomplete && $WIDGET != $LWIDGET && $ziac_prevw != $w ]]; then
ziac_matches=( $ZINIT[PLUGINS_DIR]/*${w//\//---}*(-onND[1,18]) )
ziac_prevw=$w
ziac_mt=
elif (( ziac_midx )) && [[ $WIDGET == ziac*ete && $WIDGET == $LWIDGET ]]; then
ziac_midx+=1
fi
if (( !ziac_midx || ziac_midx > $#ziac_matches )); then
ziac_midx=1
fi

REPLY=${${ziac_matches[$ziac_midx]:t}//---//}$ziac_mt
for (( i=1; i<=size; i++ )); do
# Check if we're at (i.e. directly at or after,
# when after are just spaces) current word
if [[ $i = $ZINIT_PB_SELECTED_WORD ]]; then
# Check if we're at the word itself,
# or at some distance after it
# INSERT MODE? I.e.: addition of a new token at the pointed free space?
if [[ $WIDGET == ziactioncompleteinsert ]] && (( pos > (ZINIT_PB_WORDS_BEGINNINGS[i] + ${#ZINIT_PB_WORDS[i]} - 1) )); then
# We need to introduce new word
# First move all words and spaces forward
Expand All @@ -45,6 +91,7 @@ ziactioncomplete()

# Cursor will be at end of newly added word
newcursor=$(( ZINIT_PB_WORDS_BEGINNINGS[i+1] + ${#ZINIT_PB_WORDS[i+1]} - 1 ))
# OR REPLACE MODE – substitute the match for the input/needle token
else
ZINIT_PB_WORDS[i]=$REPLY

Expand Down
12 changes: 12 additions & 0 deletions zinit.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -3236,7 +3236,19 @@ typeset -g REPLY
zinit null light-mode autoload'ziactioncomplete;ziprocessbuffer' for %$ZINIT[BIN_DIR]
zle -N ziactioncomplete
zle -N ziactioncompleteinsert ziactioncomplete
zle -N ziactioncompleteice ziactioncomplete
bindkey '\ea' ziactioncomplete
bindkey '\eA' ziactioncompleteinsert
bindkey '\ei' ziactioncompleteice

#
# Prepare a helper Zle hook
#
ziac_zle_hook() {
typeset -ga ziac_wids
ziac_wids+=( $LASTWIDGET )
}
autoload -Uz add-zle-hook-widget
add-zle-hook-widget line-pre-redraw ziac_zle_hook

# vim:ft=zsh:sw=4:sts=4:et:foldmarker=[[[,]]]:foldmethod=marker
20 changes: 11 additions & 9 deletions ziprocessbuffer
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# $2 - optional parameter containing cursor (default is $CURSOR)
#
# Output:
# ZINIT_PB_WORDS - split of "$1" into shell words; array
# ZINIT_PB_WORDS - split of $1 into shell words; array
# ZINIT_PB_WORDS_BEGINNINGS - indexes of first letters of corresponding words in ZINIT_PB_WORDS
# ZINIT_PB_SPACES - white spaces before corresponding words in ZINIT_PB_WORDS
# ZINIT_PB_SELECTED_WORD - index in ZINIT_PB_WORDS pointing to word activated by cursor position
Expand All @@ -22,10 +22,10 @@ local cursor="${2:-$CURSOR}"
ZINIT_PB_WORDS=( "${(Z+n+)buf}" )
ZINIT_PB_SPACES=( )
ZINIT_PB_WORDS_BEGINNINGS=( )
ZINIT_PB_SELECTED_WORD="-1"
ZINIT_PB_SELECTED_WORD=-1

# (Z+n+) will return 1 element for buf that is empty or only whitespace
if [[ "$buf" = ( |$'\t')# ]]; then
if [[ $buf = ( |$'\t')# ]]; then
ZINIT_PB_WORDS=( )
integer nwords=0
else
Expand Down Expand Up @@ -63,34 +63,36 @@ for (( i=1; i<=nwords; i++ )); do
# This is the beginning of current word
ZINIT_PB_WORDS_BEGINNINGS[i]=$(( char_count + 1 ))
# Remember the spaces
ZINIT_PB_SPACES[i]="$MATCH"
ZINIT_PB_SPACES[i]=$MATCH

# Remove the word
wordlen="${#word}"
[[ "${buf[1,wordlen]}" != "$word" ]] && return 1 # should not happen unless bug in (z)
[[ "${buf[1,wordlen]}" != $word ]] && return 1 # should not happen unless bug in (z)
buf="${buf[wordlen+1,-1]}"

# Spaces point to previous shell word
# Visual cursor right after spaces (-ge) -> not enough to select previous word (-gt required)
[[ "$ZINIT_PB_SELECTED_WORD" -eq "-1" && "$char_count" -gt "$cursor" ]] && ZINIT_PB_SELECTED_WORD=$(( i-1 ))
[[ $ZINIT_PB_SELECTED_WORD -eq -1 && $char_count -gt $cursor ]] && ZINIT_PB_SELECTED_WORD=$(( i-1 ))

# Actual characters point to current shell word
# Visual cursor right after letters (-ge) -> enough to select current word
char_count=char_count+"$#word"
[[ "$ZINIT_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZINIT_PB_SELECTED_WORD="$i"
[[ $ZINIT_PB_SELECTED_WORD -eq -1 && $char_count -ge $cursor ]] && ZINIT_PB_SELECTED_WORD=$i
done

# What's left in $buf can be only white spaces
char_count=char_count+"$#buf"
ZINIT_PB_SPACES[i]="$buf"
ZINIT_PB_SPACES[i]=$buf

# Visual cursor right after spaces (-ge) -> enough to select last word
[[ "$ZINIT_PB_SELECTED_WORD" -eq "-1" && "$char_count" -ge "$cursor" ]] && ZINIT_PB_SELECTED_WORD=$(( i-1 ))
[[ $ZINIT_PB_SELECTED_WORD -eq -1 && $char_count -ge $cursor ]] && ZINIT_PB_SELECTED_WORD=$(( i-1 ))

# Divide active word into two halves
integer diff=$(( cursor - ZINIT_PB_WORDS_BEGINNINGS[ZINIT_PB_SELECTED_WORD] + 1 ))
word="${ZINIT_PB_WORDS[ZINIT_PB_SELECTED_WORD]}"
ZINIT_PB_LEFT="${word[1,diff]}"
ZINIT_PB_RIGHT="${word[diff+1,-1]}"

[[ $ZINIT_PB_SELECTED_WORD -gt 0 ]]

# vim:ft=zsh

0 comments on commit 18a03d2

Please sign in to comment.