summaryrefslogtreecommitdiff
path: root/Functions
diff options
context:
space:
mode:
authormidchildan <git@midchildan.org>2024-02-29 22:34:33 +0900
committerOliver Kiddle <opk@zsh.org>2024-03-05 00:05:21 +0100
commit36a2d5cfa49a6b7d699269cb4f22d5f3d0255bc8 (patch)
tree4b0f5bec64fae4c859764deb42fe32191ce53dab /Functions
parentd1ff06f99185bb14554c6a48e0466aee6466ecac (diff)
downloadzsh-36a2d5cfa49a6b7d699269cb4f22d5f3d0255bc8.tar.gz
zsh-36a2d5cfa49a6b7d699269cb4f22d5f3d0255bc8.zip
52641: incarg: add a backward variant and make it repeatable
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Zle/incarg64
1 files changed, 57 insertions, 7 deletions
diff --git a/Functions/Zle/incarg b/Functions/Zle/incarg
index 9d56b21f6..0cfaf9ff5 100644
--- a/Functions/Zle/incarg
+++ b/Functions/Zle/incarg
@@ -41,11 +41,20 @@ emulate -L zsh
# This behaves like Vim's CTRL-A / CTRL-X. It moves the cursor to the nearest
# number after the cursor and increments or decrements it.
#
+# - vim-backward-incarg / vim-backward-decarg
+#
+# This behaves like vim-incarg & vim-decarg, but it searches backwards for a
+# number.
+#
# - vim-sync-incarg / vim-sync-decarg
#
# This combines the behavior of the vim- and sync- variants. It's inspired by
# Vim's g_CTRL-A / g_CTRL-X.
#
+# - vim-backward-sync-incarg / vim-backward-sync-decarg
+#
+# This combines the behavior of the vim-backward- and sync- variants.
+#
# Example Usage:
#
# autoload -Uz incarg
@@ -58,9 +67,13 @@ emulate -L zsh
# 'g^A' vim-sync-incarg \
# 'g^X' vim-sync-decarg
+zle -f vichange
+
setopt localoptions extended_glob
local match mbegin mend MATCH MBEGIN MEND i
+[[ -z "$BUFFER" ]] && return 1
+
# find the number and determine the base
integer pos=$(( CURSOR + 1 )) base=0
@@ -104,11 +117,35 @@ 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
+ if [[ "$WIDGET" == *backward-* ]]; then
+ # search backwards for a number
+ while true; 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 ;;
+ *[0-9]) base=10 ;;
+ *-)
+ case "$BUFFER[pos,-1]" in
+ -0[xX][0-9a-fA-F]*) ;;
+ -0[oO][0-7]*) ;;
+ -0[bB][01]*) ;;
+ -[0-9]*) base=10 ;;
+ esac
+ ;;
+ esac
+ (( base != 0 )) && break
+
+ (( pos-- ))
+ (( pos <= 0 )) && return 1
+ done
+ else
+ # jump to the nearest number after the cursor
+ while [[ "$BUFFER[pos]" == [^0-9] ]]; do
+ (( pos++ ))
+ (( pos > $#BUFFER )) && return 1
+ done
+ fi
fi
# check for a prefix right after the cursor and jump right after it, if any
@@ -204,6 +241,12 @@ fi
local old="$BUFFER[first,last]"
integer oldlen=$#BUFFER
+integer oldnum="$base#$old" 2> /dev/null
+
+# -00 should increment to 01 instead of 001
+if [[ "$BUFFER[first]" == '-' ]] && (( oldnum == 0 )); then
+ (( ndigits-- ))
+fi
local fmt1 fmt2
case "$base" in
@@ -214,10 +257,12 @@ case "$base" in
esac
local raw_result padded
+# $(( )) outputs an error message to stderr when integer truncation occurs
printf -v raw_result "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null
padded="${raw_result// /0}"
+integer newnum="$base#$padded" 2> /dev/null
-integer oldnum="$base#$old" newnum="$base#$padded" 2> /dev/null
+# try to detect integer truncation
if (( base != 10 && newnum < 0
|| delta > 0 && newnum < oldnum
|| delta < 0 && newnum > oldnum )); then
@@ -242,7 +287,12 @@ if zstyle -t ":zle:$WIDGET" debug; then
zle -M "[$WIDGET] base: $base delta: $delta old: '$old' new: '$new'"
fi
-BUFFER[first,last]="$new"
+if (( 0 < first && first <= last && last <= $#BUFFER )); then
+ BUFFER[first,last]="$new"
+else
+ zle -M "[$WIDGET] The detected location of the integer was invalid. [location=BUFFER[$first,$last]]"
+ return 1
+fi
integer offset=0
if [[ "$WIDGET" == vi* ]]; then