zsh-workers
 help / color / mirror / code / Atom feed
From: midchildan <git@midchildan.org>
To: zsh-workers@zsh.org
Cc: Oliver Kiddle <opk@zsh.org>, midchildan <git@midchildan.org>
Subject: [PATCH v3] add new features and improvements to the "incarg" ZLE widget
Date: Thu, 29 Feb 2024 04:11:41 +0900	[thread overview]
Message-ID: <frightful-dove-4211a868a2b1@midchildan> (raw)
In-Reply-To: <58899-1708011012.905219@Bjdj.O9XV.UdPU>

> If it fails to find a number going forwards in the buffer, it'd be
> useful if it could look backwards too. In contrast to an editor, the
> cursor is more often at the very end of the buffer in a shell.

I now added a new variant of the widget that consistently jumps
backward. This can be enabled by including "backward-" in the widget
name. Whether a user needs a forward or backward variant likely depends
on where the history widget places the cursor. I always need forward
jumps because the history widget I use,
history-beginning-search-backward, doesn't move the cursor. In contrast,
people using up-line-or-history need backward jumps because the cursor
goes to the end of the line.

I didn't add logic to reverse the direction when it fails to find a
number because it would complicate the implementation. The complication
comes from the fact that different logic are required for backward and
forward searching due to support for binary, octal, hexadecimal, and
negative numbers. To keep it relatively simple, the choice was to
either provide a backward variant or to only provide a forward variant
that falls back to backward jumps. I chose the former because I thought
it provided more convenience.

> I think that just adding zle -f vichange to the beginning of the
> function it will work together with vi-repeat-change (.) which brings it
> closer to ^A/^X in vim.

Thanks for the tip. I updated the patch to include this.
---
 Doc/Zsh/contrib.yo     |  33 ++-
 Functions/Zle/incarg   | 327 ++++++++++++++++++++++---
 Test/X05zleincarg.ztst | 528 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 848 insertions(+), 40 deletions(-)
 create mode 100644 Test/X05zleincarg.ztst

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index e1781a5e1..e682c800a 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -2620,12 +2620,33 @@ zle -N history-pattern-search-forward history-pattern-search)
 tindex(incarg)
 vindex(incarg, use of)
 item(tt(incarg))(
-Typing the keystrokes for this widget with the cursor placed on or to the
-left of an integer causes that integer to be incremented by one.  With a
-numeric argument, the number is incremented by the amount of the
-argument (decremented if the numeric argument is negative).  The shell
-parameter tt(incarg) may be set to change the default increment to
-something other than one.
+This widget allows you to increment integers on the current line. In addition
+to decimals, it can handle hexadecimals prefixed with tt(0x), binaries with
+tt(0b), and octals with tt(0o).
+
+By default, the target integer will be incremented by one. With a numeric
+argument, the integer is incremented by the amount of the argument. The shell
+parameter tt(incarg) may be set to change the default increment to something
+other than one.
+
+The behavior of this widget changes depending on the widget name.
+
+When the widget is named tt(incarg), the widget will increment an integer
+placed under the cursor placed or just to the left of it. tt(decarg), on the
+other hand, decrements the integer. When the name is prefixed with tt(vi),
+the cursor will jump to the nearest integer after the cursor before incrementing
+it. The tt(vi) prefix can also be combined with a tt(backward-) prefix to make
+the widget search backwards for numbers.
+
+There's also a tt(sync-) prefix that can be added to the widget name. This
+variant is used for creating a sequence of numbers on split terminals with
+synchronized key input. The first pane won't increment the integer at all, but
+each pane after that will have the integer incremented once more than the
+previous pane. It currently supports tmux and iTerm2.
+
+The prefixes tt(vi), tt(backward-), and tt(sync-) can be combined, for example,
+into tt(vim-sync-) or tt(vim-backward-sync-). The tt(vi) prefix needs to be
+at the very beginning.
 
 example(bindkey '^X+' incarg)
 )
diff --git a/Functions/Zle/incarg b/Functions/Zle/incarg
index cff0cfe4c..1f5861b79 100644
--- a/Functions/Zle/incarg
+++ b/Functions/Zle/incarg
@@ -1,43 +1,302 @@
-# Shell function to increment an integer either under the cursor or just
-# to the left of it.  Use
-#   autoload -Uz incarg
-#   zle -N incarg
-#   bindkey "..." incarg
-# to define it.  For example,
-#   echo 41
-#        ^^^ cursor anywhere here
-# with incarg gives
-#   echo 42
-# with the cursor in the same place.
-#
-# A numeric argument gives a number other than 1 to add (may be negative).
-# If you're going to do it a lot with one particular number, you can set
-# the parameter incarg to that number (a numeric argument still takes
-# precedence).
-
 emulate -L zsh
-setopt extendedglob
 
-local rrest lrest num
+# A ZLE widget to increment an integer.
+#
+# In addition to decimals, it can handle hexadecimals prefixed with "0x",
+# binaries with "0b", and octals with "0o".
+#
+# By default, the target integer will be incremented by one. With a numeric
+# argument, the integer is incremented by the amount of the argument. The shell
+# parameter "incarg" may be set to change the default increment to something
+# other than one.
+#
+# The behavior of this widget changes depending on how it is named.
+#
+# - incarg / decarg
+#
+#   incarg will increment an integer either under the cursor or just to the left
+#   of it. decarg, on the other hand, will decrement it.
+#
+#   For example,
+#
+#       echo 41
+#            ^^^ cursor anywhere here
+#
+#   with incarg gives
+#
+#       echo 42
+#              ^ cursor will move here
+#
+# - sync-incarg / sync-decarg
+#
+#   The sync- variant is used for creating a sequence of numbers on split
+#   terminals with synchronized key input. The first pane won't be incremented
+#   at all, but each pane after that will have the number incremented once more
+#   than the previous pane.
+#
+#   Currently supports tmux and iTerm2.
+#
+# - vim-incarg / vim-decarg
+#
+#   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
+#   for widget in vim-{,sync-}{inc,dec}arg; do
+#     zle -N "$widget" incarg
+#   done
+#   bindkey -a \
+#     '^A' vim-incarg \
+#     '^X' vim-decarg \
+#     'g^A' vim-sync-incarg \
+#     'g^X' vim-sync-decarg
 
-rrest=${RBUFFER##[0-9]#}
-if [[ $RBUFFER = [0-9]* ]]; then
-  if [[ -z $rrest ]]; then
-    num=$RBUFFER
-  else
-    num=${RBUFFER[1,-$#rrest-1]}
+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
+
+# 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
+    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
+  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
 
-lrest=${LBUFFER%%[0-9]#}
-if [[ $LBUFFER = *[0-9] ]]; then
-  if [[ -z $lrest ]]; then
-    num="$LBUFFER$num"
-  else
-    num="${LBUFFER[$#lrest+1,-1]}$num"
-  fi
+if (( base == 0 )); then
+  base=10
 fi
 
-[[ -n $num ]] && (( num += ${NUMERIC:-${incarg:-1}} ))
+# find the start of the number
+integer first="$pos"
+case "$base" in
+  10)
+    while [[ "$BUFFER[first-1]" == [0-9] ]]; do
+      (( first-- ))
+    done
+    if [[ $BUFFER[first-1] = - ]]; then
+      (( first-- ))
+    fi
+    ;;
+  2)
+    while [[ "$BUFFER[first-1]" == [01] ]]; do
+      (( first-- ))
+    done
+    ;;
+  8)
+    while [[ "$BUFFER[first-1]" == [0-7] ]]; do
+      (( first-- ))
+    done
+    ;;
+  16)
+    while [[ "$BUFFER[first-1]" == [0-9a-fA-F] ]]; do
+      (( first-- ))
+    done
+    ;;
+esac
 
-BUFFER="$lrest$num$rrest"
+# find the end of the number
+integer last="$pos"
+case "$base" in
+  10)
+    while [[ "$BUFFER[last+1]" == [0-9] ]]; do
+      (( last++ ))
+    done
+    ;;
+  2)
+    while [[ "$BUFFER[last+1]" == [01] ]]; do
+      (( last++ ))
+    done
+    ;;
+  8)
+    while [[ "$BUFFER[last+1]" == [0-7] ]]; do
+      (( last++ ))
+    done
+    ;;
+  16)
+    while [[ "$BUFFER[last+1]" == [0-9a-fA-F] ]]; do
+      (( last++ ))
+    done
+    ;;
+esac
+
+# 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 delta=${NUMERIC:-${incarg:-1}}
+if [[ "$WIDGET" = *decarg ]]; then
+  (( delta = -delta ))
+fi
+if [[ "$WIDGET" = *sync-* ]]; then
+  integer pane_index=0
+  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]"
+  else
+    zle -M "[$WIDGET] unsupported terminal"
+    return 1
+  fi
+  (( delta *= pane_index ))
+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 && delta > 0 )); then
+  (( ndigits-- ))
+fi
+
+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
+
+local raw_result padded
+raw_result="$( \
+  printf "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null)"
+padded="${raw_result// /0}"
+integer newnum="$base#$padded" 2> /dev/null
+
+if (( base != 10 && newnum < 0
+        || 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
+
+# adjust the number of leading zeros if the sign of the integer changed
+local new
+if (( base == 10 && ndigits == $#padded )); then
+  if (( oldnum < 0 && newnum >= 0 )); then
+    new="${padded#0}"
+  elif (( oldnum >= 0 && newnum < 0 )); then
+    new="-0${padded#-}"
+  fi
+fi
+if [[ -z "$new" ]]; then
+  new="$padded"
+fi
+
+if zstyle -t ":zle:$WIDGET" debug; then
+  zle -M "[$WIDGET] base: $base delta: $delta old: '$old' new: '$new'"
+fi
+
+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
+  offset=-1
+fi
+(( CURSOR = last + $#BUFFER - oldlen + offset ))
+
+return 0
diff --git a/Test/X05zleincarg.ztst b/Test/X05zleincarg.ztst
new file mode 100644
index 000000000..50a450734
--- /dev/null
+++ b/Test/X05zleincarg.ztst
@@ -0,0 +1,528 @@
+# Tests the incarg ZLE widget
+
+%prep
+  ZSH_TEST_LANG=$(ZTST_find_UTF8)
+  if ( zmodload zsh/zpty 2>/dev/null ); then
+    . $ZTST_srcdir/comptest
+    comptestinit -v -z $ZTST_testdir/../Src/zsh
+  else
+    ZTST_unimplemented="the zsh/zpty module is not available"
+  fi
+  zpty_run '
+    autoload -Uz incarg
+    for name in {,vim-,vim-backward-}{,sync-}{inc,dec}arg; do
+      zle -N "$name" incarg
+    done
+    bindkey -v "^N" incarg
+    bindkey -v "^P" decarg
+    bindkey -v "^F" sync-incarg
+    bindkey -v "^B" sync-decarg
+    bindkey -a "^N" vim-incarg
+    bindkey -a "^P" vim-decarg
+    bindkey -a "^F" vim-sync-incarg
+    bindkey -a "^B" vim-sync-decarg
+    bindkey -a "^E" vim-backward-incarg
+    bindkey -a "^Y" vim-backward-decarg
+    unset TMUX_PANE ITERM_SESSION_ID
+    tmux() {
+      echo "$TMUX_PANE"
+    }
+  '
+
+%test
+
+# Basic increment & decrement
+
+  zletest $'0\C-n'
+0:incarg increments an integer
+>BUFFER: 1
+>CURSOR: 1
+
+  zletest $'0\C-p'
+0:decarg decrements an integer
+>BUFFER: -1
+>CURSOR: 2
+
+  zletest $'echo 0\e0\C-n'
+0:vim-incarg increments an integer
+>BUFFER: echo 1
+>CURSOR: 5
+
+  zletest $'echo 0\e0\C-p'
+0:vim-decarg decrements an integer
+>BUFFER: echo -1
+>CURSOR: 6
+
+  zletest $'echo 0 foo\e\C-e'
+0:vim-backward-incarg increments an integer
+>BUFFER: echo 1 foo
+>CURSOR: 5
+
+  zletest $'echo 0 foo\e\C-y'
+0:vim-backward-decarg decrements an integer
+>BUFFER: echo -1 foo
+>CURSOR: 6
+
+# sync- variants
+
+  zletest $'0\C-f'
+0:sync-incarg does nothing on unsupported terminals
+>BUFFER: 0
+>CURSOR: 1
+
+  zpty_run 'TMUX_PANE=0'
+  zletest $'0\C-f'
+  zpty_run 'unset TMUX_PANE'
+0:sync-incarg does nothing on tmux in pane 0
+>BUFFER: 0
+>CURSOR: 1
+
+  zpty_run 'TMUX_PANE=1'
+  zletest $'0\C-f'
+  zpty_run 'unset TMUX_PANE'
+0:sync-incarg increments by 1 on tmux in pane 1
+>BUFFER: 1
+>CURSOR: 1
+
+  zpty_run 'TMUX_PANE=2'
+  zletest $'0\C-f'
+  zpty_run 'unset TMUX_PANE'
+0:sync-incarg increments by 2 on tmux in pane 2
+>BUFFER: 2
+>CURSOR: 1
+
+  zpty_run 'ITERM_SESSION_ID=w0t0p0:00000000-0000-0000-0000-000000000000'
+  zletest $'0\C-f'
+  zpty_run 'unset ITERM_SESSION_ID'
+0:sync-incarg does nothing on tmux in pane 0
+>BUFFER: 0
+>CURSOR: 1
+
+  zpty_run 'ITERM_SESSION_ID=w0t0p1:00000000-0000-0000-0000-000000000000'
+  zletest $'0\C-f'
+  zpty_run 'unset ITERM_SESSION_ID'
+0:sync-incarg increments by 1 on tmux in pane 1
+>BUFFER: 1
+>CURSOR: 1
+
+  zpty_run 'ITERM_SESSION_ID=w0t0p2:00000000-0000-0000-0000-000000000000'
+  zletest $'0\C-f'
+  zpty_run 'unset ITERM_SESSION_ID'
+0:sync-incarg increments by 2 on tmux in pane 2
+>BUFFER: 2
+>CURSOR: 1
+
+  zpty_run 'TMUX_PANE=1'
+  zpty_run 'ITERM_SESSION_ID=w0t0p2:00000000-0000-0000-0000-000000000000'
+  zletest $'0\C-f'
+  zpty_run 'unset TMUX_PANE ITERM_SESSION_ID'
+0:sync-incarg prioritizes tmux pane number over iTerm2's
+>BUFFER: 1
+>CURSOR: 1
+
+  zletest $'0\e2\C-n'
+0:incarg changes the incremented amount based on the numeric argument
+>BUFFER: 2
+>CURSOR: 0
+
+  zpty_run 'incarg=3'
+  zletest $'0\e\C-n'
+  zpty_run 'unset incarg'
+0:incarg changes the default incremented amount based on the incarg variable
+>BUFFER: 3
+>CURSOR: 0
+
+  zpty_run 'incarg=3'
+  zletest $'0\e2\C-n'
+  zpty_run 'unset incarg'
+0:incarg prioritizes the numeric argument over the incarg variable
+>BUFFER: 2
+>CURSOR: 0
+
+  zpty_run 'TMUX_PANE=2'
+  zletest $'0\e2\C-f'
+  zpty_run 'unset TMUX_PANE'
+0:The sync- variants of incarg takes the numeric argument into account
+>BUFFER: 4
+>CURSOR: 0
+
+# Leading zeros
+
+  zletest $'000\C-n'
+0:incarg preserves leading zeros of decimal integers
+>BUFFER: 001
+>CURSOR: 3
+
+  zletest $'-001\C-n\C-n'
+0:incarg preserves leading zeros when the digit turns from negative to positive
+>BUFFER: 001
+>CURSOR: 3
+
+  zletest $'001\C-p\C-p'
+0:incarg preserves leading zeros when the digit turns from positive to negative
+>BUFFER: -001
+>CURSOR: 4
+
+  zletest $'001\e1000\C-n'
+0:incarg works when the result has more number of digits than the original
+>BUFFER: 1001
+>CURSOR: 3
+
+  zletest $'001\e2000\C-p'
+0:decargs works on integers with leading zeros when the result has more digits than the original
+>BUFFER: -1999
+>CURSOR: 4
+
+# Binaries
+
+  zletest $'0b11\C-n'
+0:incarg can increment a binary integer
+>BUFFER: 0b100
+>CURSOR: 5
+
+  zletest $'0B11\C-n'
+0:incarg can increment a binary integer with an upper case prefix
+>BUFFER: 0B100
+>CURSOR: 5
+
+  zletest $'0b100\C-p'
+0:decarg can decrement a binary integer
+>BUFFER: 0b11
+>CURSOR: 4
+
+  zletest $'0b0011\C-n'
+0:incarg can preserve leading zeros of binaries
+>BUFFER: 0b0100
+>CURSOR: 6
+
+  zletest $'0b001\e8\C-n'
+0:incarg works on binaries when the result has more zeros than the original
+>BUFFER: 0b1001
+>CURSOR: 5
+
+  zletest $'0b0\C-p'
+0:decarg fails to produce a negative binary value
+>BUFFER: 0b0
+>CURSOR: 3
+
+# Octals
+
+  zletest $'0o7\C-n'
+0:incarg can increment an octal integer
+>BUFFER: 0o10
+>CURSOR: 4
+
+  zletest $'0O7\C-n'
+0:incarg can increment an octal integer with an upper case prefix
+>BUFFER: 0O10
+>CURSOR: 4
+
+  zletest $'0o10\C-p'
+0:decarg can decrement an octal integer
+>BUFFER: 0o7
+>CURSOR: 3
+
+  zletest $'0o0\C-p'
+0:decarg fails to produce a negative octal value
+>BUFFER: 0o0
+>CURSOR: 3
+
+# Hexadecimals
+
+  zletest $'0x9\C-n'
+0:incarg can increment a hexadecimal integer
+>BUFFER: 0xa
+>CURSOR: 3
+
+  zletest $'0X9\C-n'
+0:incarg can increment a hexadecimal integer with an upper case prefix
+>BUFFER: 0XA
+>CURSOR: 3
+
+  zletest $'0xf\C-n'
+0:incarg can increment a hexadecimal integer with no numeric digit
+>BUFFER: 0x10
+>CURSOR: 4
+
+  zletest $'0x10\C-p'
+0:decarg can decrement a hexadecimal integer
+>BUFFER: 0xf
+>CURSOR: 3
+
+  zletest $'0x0\C-p'
+0:decarg fails to produce a negative hexadecimal value
+>BUFFER: 0x0
+>CURSOR: 3
+
+  zletest $'0x0b1\C-n'
+0:incarg interprets integers starting with 0x0b as a hexadecimal
+>BUFFER: 0x0b2
+>CURSOR: 5
+
+  zletest $'0x0b1\e\C-e'
+0:vim-backward-incarg interprets integers starting with 0x0b as a hexadecimal
+>BUFFER: 0x0b2
+>CURSOR: 4
+
+# Cursor position - incarg
+
+  zletest $'echo 012ab\eF i\C-n'
+0:incarg does nothing when the cursor is placed just to the left of an integer
+>BUFFER: echo 012ab
+>CURSOR: 4
+
+  zletest $'echo 012ab\eF0i\C-n'
+0:incarg works when the cursor is placed at the leftmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 8
+
+  zletest $'echo 012ab\eF1i\C-n'
+0:incarg works when the cursor is placed at the inner digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 8
+
+  zletest $'echo 012ab\eF2i\C-n'
+0:incarg works when the cursor is placed at the rightmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 8
+
+  zletest $'echo 012ab\eFai\C-n'
+0:incarg works when the cursor is placed just to the right of an integer
+>BUFFER: echo 013ab
+>CURSOR: 8
+
+  zletest $'echo 012ab\ei\C-n'
+0:incarg does nothing when the cursor is placed more than a single letter away to the right
+>BUFFER: echo 012ab
+>CURSOR: 9
+
+  zletest $'10x9\e0\C-n'
+0:incarg turns [0-9]0x[0-9a-f] into [0-9]1x[0-9a-f] when the cursor is at the left of x
+>BUFFER: 11x9
+>CURSOR: 1
+
+  zletest $'10x9\eFx\C-n'
+0:incarg takes [0-9]0x[0-9a-f] and increments the hexadecimal part when the cursor is on x
+>BUFFER: 10xa
+>CURSOR: 3
+
+  zletest $'10x9\e\C-n'
+0:incarg takes [0-9]0x[0-9a-f] and increments the hexadecimal part when the cursor is at the right of x
+>BUFFER: 10xa
+>CURSOR: 3
+
+  zletest $'10b1\e0\C-n'
+0:incarg turns [0-9]0b[01] into [0-9]1b[01] when the cursor is at the left of b
+>BUFFER: 11b1
+>CURSOR: 1
+
+  zletest $'10b1\eFb\C-n'
+0:incarg takes [0-9]0b[01] and increments the binary part when the cursor is on b
+>BUFFER: 10b10
+>CURSOR: 4
+
+  zletest $'10b1\e\C-n'
+0:incarg takes [0-9]0b[01] and increments binary part when the cursor is at the right of b
+>BUFFER: 10b10
+>CURSOR: 4
+
+  zletest $'10o7\e0\C-n'
+0:incarg turns [0-9]0o[0-7] into [0-9]1o[0-7] when the cursor is at the left of o
+>BUFFER: 11o7
+>CURSOR: 1
+
+  zletest $'10o7\eFo\C-n'
+0:incarg takes [0-9]0o[0-7] and increments the octal part when the cursor is on o
+>BUFFER: 10o10
+>CURSOR: 4
+
+  zletest $'10o7\e\C-n'
+0:incarg takes [0-9]0o[0-7] and increments the octal part when the cursor is at the right of o
+>BUFFER: 10o10
+>CURSOR: 4
+
+  zletest $'0b0x9\eF0\C-n'
+0:incarg takes 0b0x[0-9a-f] and increments the binary part when the cursor is at the left of x
+>BUFFER: 0b1x9
+>CURSOR: 2
+
+  zletest $'0b0x9\eFx\C-n'
+0:incarg takes 0b0x[0-9a-f] and increments the hexadecimal part when the cursor is on x
+>BUFFER: 0b0xa
+>CURSOR: 4
+
+  zletest $'0b0x9\e\C-n'
+0:incarg takes 0b0x[0-9a-f] and increments the hexadecimal part when the cursor is at the right of x
+>BUFFER: 0b0xa
+>CURSOR: 4
+
+# Cursor position - vim-incarg
+
+  zletest $'echo 012ab\eF \C-n'
+0:vim-incarg works when the cursor is placed to the left of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eF0\C-n'
+0:vim-incarg works when the cursor is placed at the leftmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eF1\C-n'
+0:vim-incarg works when the cursor is placed at the inner digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eF2\C-n'
+0:incarg works when the cursor is placed at the rightmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eFa\C-n'
+0:vim-incarg does nothing when the cursor is placed to the right of an integer
+>BUFFER: echo 012ab
+>CURSOR: 8
+
+  zletest $'echo 012ab\ei\C-n'
+0:vim-incarg does nothing when the cursor is placed more than a single letter away to the right
+>BUFFER: echo 012ab
+>CURSOR: 9
+
+# Cursor position - vim-backward-incarg
+
+  zletest $'echo 012ab\eF \C-e'
+0:vim-backward-incarg does nothing when the cursor is placed just to the left of an integer
+>BUFFER: echo 012ab
+>CURSOR: 4
+
+  zletest $'echo 012ab\eF0\C-e'
+0:vim-backward-incarg works when the cursor is placed at the leftmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eF1\C-e'
+0:vim-backward-incarg works when the cursor is placed at the inner digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eF2\C-e'
+0:vim-backward-incarg works when the cursor is placed at the rightmost digit of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\eFa\C-e'
+0:vim-backward-incarg works when the cursor is placed just to the right of an integer
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'echo 012ab\e\C-e'
+0:vim-backward-incarg works when the cursor is placed more than a single letter away to the right
+>BUFFER: echo 013ab
+>CURSOR: 7
+
+  zletest $'10x9\eFx\C-e'
+0:vim-backward-incarg will take [0-9]0x[0-9a-f] and increment the hexadecimal part when the cursor is on x
+>BUFFER: 10xa
+>CURSOR: 3
+
+  zletest $'10x9\e\C-e'
+0:vim-backward-incarg will take [0-9]0x[0-9a-f] and increment the hexadecimal part when the cursor is on the right of x
+>BUFFER: 10xa
+>CURSOR: 3
+
+  zletest $'10b1\e0\C-e'
+0:vim-backward-incarg will turn [0-9]0b[01] into [0-9]1b[01] when the cursor is at the left of b
+>BUFFER: 11b1
+>CURSOR: 1
+
+  zletest $'10b1\eFb\C-e'
+0:vim-backward-incarg will take [0-9]0b[01] and increment the binary part when the cursor is on b
+>BUFFER: 10b10
+>CURSOR: 4
+
+  zletest $'10b1\e\C-e'
+0:vim-backward-incarg will take [0-9]0b[01] and increment the binary part when the cursor is on the right of b
+>BUFFER: 10b10
+>CURSOR: 4
+
+  zletest $'10o7\e0\C-e'
+0:vim-backward-incarg will turn [0-9]0o[0-7] into [0-9]1o[0-7] when the cursor is at the left of o
+>BUFFER: 11o7
+>CURSOR: 1
+
+  zletest $'10o7\eFo\C-e'
+0:vim-backward-incarg will take [0-9]0o[0-7] and increment the octal part when the cursor is on o
+>BUFFER: 10o10
+>CURSOR: 4
+
+  zletest $'10o7\e\C-e'
+0:vim-backward-incarg will take [0-9]0o[0-7] and increment the octal part when the cursor is at the right of o
+>BUFFER: 10o10
+>CURSOR: 4
+
+  zletest $'0b0x9\eF0\C-e'
+0:vim-backward-incarg will take 0b0x[0-9a-f] and increment the binary 0b0 when the cursor is on the left of x
+>BUFFER: 0b1x9
+>CURSOR: 2
+
+  zletest $'0b0x9\eFx\C-e'
+0:vim-backward-incarg will take 0b0x[0-9a-f] and increment the hexadecimal part when the cursor is on x
+>BUFFER: 0b0xa
+>CURSOR: 4
+
+  zletest $'0b0x9\e\C-e'
+0:vim-backward-incarg will take 0b0x[0-9a-f] and increment the hexadecimal part when the cursor is at the right of x
+>BUFFER: 0b0xa
+>CURSOR: 4
+
+# Repeats
+
+  zletest $'echo 0\e0\C-n.'
+0:vim-incarg is compatible with the repeat command
+>BUFFER: echo 2
+>CURSOR: 5
+
+  zletest $'echo 0\e0\C-p.'
+0:vim-decarg is compatible with the repeat command
+>BUFFER: echo -2
+>CURSOR: 6
+
+  zletest $'echo 0 foo\e\C-e.'
+0:vim-backward-incarg is compatible with the repeat command
+>BUFFER: echo 2 foo
+>CURSOR: 5
+
+  zletest $'echo 0\e010\C-n.'
+0:Repeats of vim-incarg takes the numeric argument into account
+>BUFFER: echo 20
+>CURSOR: 6
+
+  zletest $'echo 0 foo\e10\C-e.'
+0:Repeats of vim-backward-incarg takes the numeric argument into account
+>BUFFER: echo 20 foo
+>CURSOR: 6
+
+  zpty_run 'TMUX_PANE=0'
+  zletest $'echo 0\e0\C-f.'
+  zpty_run 'unset TMUX_PANE'
+0:Repeats of vim-sync-incarg work in pane 0
+>BUFFER: echo 0
+>CURSOR: 5
+
+  zpty_run 'TMUX_PANE=1'
+  zletest $'echo 0\e0\C-f.'
+  zpty_run 'unset TMUX_PANE'
+0:Repeats of vim-sync-incarg work in pane 1
+>BUFFER: echo 2
+>CURSOR: 5
+
+  zpty_run 'TMUX_PANE=2'
+  zletest $'echo 0\e0\C-f.'
+  zpty_run 'unset TMUX_PANE'
+0:Repeats of vim-sync-incarg work in pane 2
+>BUFFER: echo 4
+>CURSOR: 5
+
+%clean
+
+  zmodload -ui zsh/zpty

base-commit: 698af7bc1387462c8e87767d7eaeb7e30c6f0b2b


  reply	other threads:[~2024-02-28 19:13 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-04 19:19 [PATCH] " midchildan
2024-02-05  0:36 ` Bart Schaefer
2024-02-05 16:16   ` midchildan
2024-02-15 15:30 ` Oliver Kiddle
2024-02-28 19:11   ` midchildan [this message]
2024-02-28 20:07     ` [PATCH] incarg: add a backward variant and make it repeatable midchildan
2024-02-29 13:34       ` [PATCH v2] " midchildan
2024-03-04 23:20         ` Oliver Kiddle
2024-03-28 23:07           ` Sho Yuhara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=frightful-dove-4211a868a2b1@midchildan \
    --to=git@midchildan.org \
    --cc=opk@zsh.org \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).