From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-3.3 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: from zero.zsh.org (zero.zsh.org [IPv6:2a02:898:31:0:48:4558:7a:7368]) by inbox.vuxu.org (Postfix) with ESMTP id E6D9925E74 for ; Wed, 28 Feb 2024 20:13:06 +0100 (CET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=zsh.org; s=rsa-20210803; t=1709147586; b=MYYCJcQDla7WlXGm7V1KREKdkss9YqStUOhLwunpftHRcFis7YkUgdSjGQ/34EYBY/F/HV5Ncp vJYCIsNTzGfBkO1thai1wqNjnUMZ1tJBEkgo7SmnqoCAhM2oBVtIxbP2iVw+hi470CnDvD2DAC 19Y7+YFBdxVnNDjhCc2uz0UsL/1QjhWV4Hi2V9LvDooamGH8B/WQ/Rc3cKjJlybs7oXVvt+bOw rhm6UAee7cbVDvRNgwp932CWarSdtGcX+WKLeArmawjPaMsF/HgBmAndg5haP9CRMhDuXxr6Sj 4Cb3GH6zK74wkkyMK6zSjr+MvSKV4Me4+rC83pW4q/Zn4w==; ARC-Authentication-Results: i=1; zsh.org; iprev=pass (wout5-smtp.messagingengine.com) smtp.remote-ip=64.147.123.21; dkim=pass header.d=midchildan.org header.s=fm3 header.a=rsa-sha256; dkim=pass header.d=messagingengine.com header.s=fm1 header.a=rsa-sha256; dmarc=none header.from=midchildan.org; arc=none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed; d=zsh.org; s=rsa-20210803; t=1709147586; bh=yMje6fwswl9UxJMh50m6fSEOuCTw+1mPtbqI4fD1xPo=; h=List-Archive:List-Owner:List-Post:List-Unsubscribe:List-Subscribe:List-Help: List-Id:Sender:Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:DKIM-Signature: DKIM-Signature:DKIM-Signature; b=O+uQKW14LPhSR4nQoTAZ7RpGkkR93wSzcgbUO4rifC6ytHlep0fHeXx9NEWcUjV0+V8a7mbFNF PhsiHQ2i2p+mQvcX90kMZA2UnHZ50v7pauBoLNp/l19+F0HpQC+AWDBQD4J1cxZEGqds2ZTVxl 5jLlkypw+IkuqEeUsFYYE79uh1XaH56rRRoY4+9FvFJitLKCYQ2B3qNCvtdz4NMRMaTGvLqiva TwOr5nE0SHJWl8gc3FGdDg3NvigKdXL1scNjU83K3qZyWOAZtE1zNRHbyeNuoiPWVxldig8PL8 5kQtCqoIWssp/73lzSQuQgKdzgQrIxR6DUTgULOWewiZIw==; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=zsh.org; s=rsa-20210803; h=List-Archive:List-Owner:List-Post:List-Unsubscribe: List-Subscribe:List-Help:List-Id:Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID; bh=B3APkFFhC5RaOUvd5bIfiThCBT4vm4UX4+kjCNnKioQ=; b=gqxOs0/cmXSeLFcRo6TT4+QsbE mysEs67JPiB1VtbH8EHeEqPn8Ju0b3Kx+LMccKC5wTVgdxD3unpOHjSFQ++RCxnR25FAi7A13nxi0 8NQJ4nSKonfUIFjUvAmF61KSG6gmX0F5ZgBjUFEqlfrI/haDS0sR9XmONPjK5ibFgoJPx5ar0WXjl ZByLGybO0Muztj1vdhYXzu0NPmB4d8HvfJGIPo/a6v+O+H5I0IxP83xhYLEES7qTFtIJ6I420jBqQ +DdXF7ND45u9tdxKNUYx6Fz9+dVpK4ykKYTTtn0H5bWwA4Q3vDONGYtHBydgFl5aGAwsWY5w9r2GM nGjLJFnw==; Received: by zero.zsh.org with local id 1rfPMY-000OgG-5X; Wed, 28 Feb 2024 19:13:06 +0000 Authentication-Results: zsh.org; iprev=pass (wout5-smtp.messagingengine.com) smtp.remote-ip=64.147.123.21; dkim=pass header.d=midchildan.org header.s=fm3 header.a=rsa-sha256; dkim=pass header.d=messagingengine.com header.s=fm1 header.a=rsa-sha256; dmarc=none header.from=midchildan.org; arc=none Received: from wout5-smtp.messagingengine.com ([64.147.123.21]:35467) by zero.zsh.org with esmtps (TLS1.3:TLS_AES_256_GCM_SHA384:256) id 1rfPLq-000OL2-1H; Wed, 28 Feb 2024 19:12:24 +0000 Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 4655C3200A24; Wed, 28 Feb 2024 14:12:19 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Wed, 28 Feb 2024 14:12:19 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=midchildan.org; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm3; t=1709147538; x= 1709233938; bh=B3APkFFhC5RaOUvd5bIfiThCBT4vm4UX4+kjCNnKioQ=; b=E OchMSY9l2LBHgsgCXMRdfp2FmNQKTgr9yVTNo63WV6q0Jilf8LQq7Rapxe7i610g 4JV7fb8Ipbcak6fHKq6UF/XdxHmnoNpMqJ/XQmReYmgZHyzdyAFJh5DizZyJXLNq qzkQ2GsQsVqZO7Y15EkGEkMcn9+leqSWbMovkeFeWcngXO4szx2TNDNfFAw6shIk +taP4bf0hplBovySOT3YK8sdFvD+nJILPdjeSW7+MNZNNXsvtR+HcvkcFBriMixx 4UD2K5B7r3iXcsUKazKbssuPNqMqEMpW+zRt2nYLw7T1MtYJdRZlnkUx2wEFi57/ VQTV+kQQ1dsuqMuBYUSQQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1709147538; x= 1709233938; bh=B3APkFFhC5RaOUvd5bIfiThCBT4vm4UX4+kjCNnKioQ=; b=I hXcIvMKeMFhhVImuHI4kHeigbdyF8ORVrg+cCM8DEq+bRDT+UcB08xh7rISV3jyB wLSyLakcB3QoUlcfhJLVLw9OVIXNux0XKyyAORn2HeSECoClXFGmKnfEC5MGJ6Qz b4mfzatPi0JY2GpqI2ZdWfL5AJ2g850KABWkfiV8zT1T1YmgRvwiwYwCMiIu1ysk rRBaj7jhKkbAvLQk4KO49zQ+3DTI2AOGJJ4BNthtTCnh7H4XzzCxvPZNYuZCIlRX nHg6SKo8MfzipmfrInd24v2imjnJbZSzlT2Q1w8nZO1hY1amaZVx8NT0G83qTIqw E3KbsFISKQ3RDfGhf9grw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrgeejgdduudejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefhvfevufffkfgjfhgggfestdekre dttddttdenucfhrhhomhepmhhiuggthhhilhgurghnuceoghhithesmhhiuggthhhilhgu rghnrdhorhhgqeenucggtffrrghtthgvrhhnpedugfffgeffieekgeekvdeihfduffdvhf fgkeefuefhffegueettdektdffgeduieenucevlhhushhtvghrufhiiigvpedtnecurfgr rhgrmhepmhgrihhlfhhrohhmpehgihhtsehmihgutghhihhluggrnhdrohhrgh X-ME-Proxy: Feedback-ID: i970949fb:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 28 Feb 2024 14:12:16 -0500 (EST) From: midchildan To: zsh-workers@zsh.org Cc: Oliver Kiddle , midchildan Subject: [PATCH v3] add new features and improvements to the "incarg" ZLE widget Date: Thu, 29 Feb 2024 04:11:41 +0900 Message-Id: In-Reply-To: <58899-1708011012.905219@Bjdj.O9XV.UdPU> References: <58899-1708011012.905219@Bjdj.O9XV.UdPU> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Seq: 52636 Archived-At: X-Loop: zsh-workers@zsh.org Errors-To: zsh-workers-owner@zsh.org Precedence: list Precedence: bulk Sender: zsh-workers-request@zsh.org X-no-archive: yes List-Id: List-Help: , List-Subscribe: , List-Unsubscribe: , List-Post: List-Owner: List-Archive: > 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