Skip to content

Commit

Permalink
feat(zsh/vim-incarg): add compatibilty with zsh's stock incarg
Browse files Browse the repository at this point in the history
  • Loading branch information
midchildan committed Jan 27, 2024
1 parent 5473c67 commit 6c62456
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 55 deletions.
145 changes: 94 additions & 51 deletions files/.local/share/zsh/site-functions/vim-incarg
Original file line number Diff line number Diff line change
@@ -1,47 +1,71 @@
emulate -L zsh

setopt localoptions extended_glob
local match mbegin mend MATCH MBEGIN MEND
local match mbegin mend MATCH MBEGIN MEND i

# find the number and determine the base
integer pos=$(( CURSOR + 1 )) base=10
case "$BUFFER[1,pos]" in
*0[xX][0-9a-fA-F]#)
if [[ "$BUFFER[pos]" != [xX] || "$BUFFER[post+1]" == [0-9a-fA-F] ]]; then
base=16
fi
;;
*0[oO][0-7]#)
if [[ "$BUFFER[pos]" != [oO] || "$BUFFER[post+1]" == [0-7] ]]; then
base=8
fi
;;
*0[bB][01]#)
if [[ "$BUFFER[pos]" != [xX] || "$BUFFER[post+1]" == [01] ]]; then
base=2
fi
;;
esac
if (( base == 10 )); then
while [[ "$BUFFER[pos]" != [0-9] ]]; do
(( pos++ ))
(( pos > $#BUFFER )) && return
done
integer pos=$(( CURSOR + 1 )) base=0

# avoid miscalculating positions when cursor is at the end of the line
while (( pos > 0 )) && [[ "$BUFFER[pos]" == '' ]]; do
(( pos-- ))
done

# check for a prefix (e.g., 0x) before the cursor
for (( i = 0; i < 2; i++ )); do
case "$BUFFER[1,pos]" in
*0[xX][0-9a-fA-F]##) base=16 ;;
*0[oO][0-7]##) base=8 ;;
*0[bB][01]##) base=2 ;;
*[1-9]) base=10 ;;
*0) ;; # there may be a prefix right after the cursor
*)
# the non-Vim variant looks right before the cursor too, but not after it
if [[ "$WIDGET" != vi* ]]; then
if (( i == 0 )); then
(( pos-- ))
continue
else
return 1
fi
fi
;;
esac

break
done

# check for a prefix on the cursor
if (( base == 0 && pos < $#BUFFER )); then
case "$BUFFER[1,pos+1]" in
*0[xX][0-9a-fA-F]) base=16; (( pos++ )) ;;
*0[oO][0-7]) base=8; (( pos++ )) ;;
*0[bB][01]) base=2; (( pos++ )) ;;
esac
fi

if (( base == 0 )); then
if [[ "$WIDGET" == vi* ]]; then
# jump to the nearest number after the cursor
while [[ "$BUFFER[pos]" == [^0-9] ]]; do
(( pos++ ))
(( pos > $#BUFFER )) && return 1
done
fi

# check for a prefix right after the cursor and jump right after it, if any
if (( pos <= 1 )) || [[ "$BUFFER[pos-1]" == [^0-9] ]]; then
case "$BUFFER[pos,-1]" in
0[xX][0-9a-fA-F]*) base=16; (( pos += 2 )) ;;
0[oO][0-7]*) base=8; (( pos += 2 )) ;;
0[bB][01]*) base=2; (( pos += 2 )) ;;
esac
fi
fi

if (( base == 0 )); then
base=10
fi
case "$BUFFER[pos,-1]" in
0[xX][0-9a-fA-F]*)
base=16
(( pos += 2 ))
;;
0[oO][0-7]*)
base=8
(( pos += 2 ))
;;
0[bB][01]*)
base=2
(( pos += 2 ))
;;
esac

# find the start of the number
integer first="$pos"
Expand Down Expand Up @@ -96,40 +120,59 @@ case "$base" in
;;
esac

# calculate the width
# calculate the number of digits
integer ndigits=0
case "$BUFFER[first,first+1]" in
0*|-0) ndigits=$(( last - first + 1 )) ;;
esac

# determine the amount to increment
integer ninc=${NUMERIC:-1}
integer delta=${NUMERIC:-1}
if [[ "$WIDGET" = *decarg ]]; then
(( ninc = -ninc ))
(( delta = -delta ))
fi
if [[ "$WIDGET" = sync-* ]]; then
if [[ "$WIDGET" = *sync-* ]]; then
integer pane_index=1
if [[ -n "$TMUX_PANE" ]]; then
pane_index="$(tmux display-message -pt "$TMUX_PANE" '#{pane_index}')"
elif [[ "$ITERM_SESSION_ID" =~ '^w[0-9]+t[0-9]+p([0-9]+)' ]]; then
pane_index=$match[1]
pane_index="$match[1]"
fi
(( ninc *= pane_index ))
(( delta *= pane_index ))
fi

local fmt1 fmt2 result
local old="$BUFFER[first,last]"
integer oldlen=$#BUFFER

local fmt1 fmt2
case "$base" in
10) fmt1=d; fmt2='#10' ;;
2) fmt1=s; fmt2='##2' ;;
8) fmt1=s; fmt2='##8' ;;
16) fmt1="$BUFFER[first-1]"; fmt2='#16' ;;
esac
# ignore overflows because there's no way to query the size of integers
result="$(printf "%0$ndigits$fmt1" $(( [$fmt2] "$base#$BUFFER[first,last]" + ninc )) 2> /dev/null)"

# change the number and move the cursor after it
integer oldlen=$#BUFFER
BUFFER[first,last]="${result// /0}"
(( CURSOR = last + $#BUFFER - oldlen - 1 ))
local raw_result new
raw_result="$( \
printf "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null)"
new="${raw_result// /0}"

if zstyle -t ":zle:$WIDGET" debug; then
zle -M "[$WIDGET] base: $base delta: $delta old: '$old' new: '$new'"
fi

integer oldnum="$base#$old" newnum="$base#$new" 2> /dev/null
if (( delta > 0 && newnum < oldnum || delta < 0 && newnum > oldnum )); then
zle -M "[$WIDGET] The resulting number is either too big or too small."
return 1
fi

BUFFER[first,last]="$new"

integer offset=0
if [[ "$WIDGET" == vi* ]]; then
offset=-1
fi
(( CURSOR = last + $#BUFFER - oldlen + offset ))

return 0
8 changes: 4 additions & 4 deletions files/.zshrc
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ autoload -Uz surround \
autoload -Uz vim-incarg \
&& zle -N vim-incarg \
&& zle -N vim-decarg vim-incarg \
&& zle -N sync-incarg vim-incarg \
&& zle -N sync-decarg vim-incarg
&& zle -N vim-sync-incarg vim-incarg \
&& zle -N vim-sync-decarg vim-incarg

(( $+aliases[run-help] )) && unalias run-help
autoload -Uz run-help run-help-{git,ip,openssl,sudo,gh,nix}
Expand Down Expand Up @@ -177,8 +177,8 @@ bindkey -v \
'^?' backward-delete-char
bindkey -ra 's'
bindkey -a \
'g^A' sync-incarg \
'g^X' sync-decarg \
'g^A' vim-sync-incarg \
'g^X' vim-sync-decarg \
'sa' add-surround \
'sd' delete-surround \
'sr' change-surround \
Expand Down

0 comments on commit 6c62456

Please sign in to comment.