From 84dde7c7b622737a34526ac2a5ba29ddc6c072d8 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 14 May 2022 20:34:28 -0700 Subject: Jan Brieg: 50212 (and discussion): Add "bright" color variants --- Functions/Misc/colors | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/Functions/Misc/colors b/Functions/Misc/colors index 5e9d77d10..5c9924adb 100644 --- a/Functions/Misc/colors +++ b/Functions/Misc/colors @@ -63,6 +63,16 @@ color=( # 63 double-overline-or-left # 64 stress # 65 no-ideogram-marking + +# Bright color codes (xterm extension) + 90 bright-gray 100 bg-bright-gray + 91 bright-red 101 bg-bright-red + 92 bright-green 102 bg-bright-green + 93 bright-yellow 103 bg-bright-yellow + 94 bright-blue 104 bg-bright-blue + 95 bright-magenta 105 bg-bright-magenta + 96 bright-cyan 106 bg-bright-cyan + 97 bright-white 107 bg-bright-white ) # A word about black and white: The "normal" shade of white is really a @@ -79,7 +89,7 @@ for k in ${(k)color}; do color[${color[$k]}]=$k; done # Add "fg-" keys for all the text colors, for clarity. -for k in ${color[(I)3?]}; do color[fg-${color[$k]}]=$k; done +for k in ${color[(I)[39]?]}; do color[fg-${color[$k]}]=$k; done # This is inaccurate, but the prompt theme system needs it. @@ -89,7 +99,11 @@ for k in grey gray; do color[bg-$k]=${color[bg-black]} done -# Assistance for the color-blind. +# Assistance for the colo(u)r-blind. + +for k in '' fg- bg-; do + color[${k}bright-grey]=${color[${k}bright-gray]} +done colour=(${(kv)color}) # A case where ksh namerefs would be useful ... -- cgit v1.2.3 From 92da264eea88582d51c9932b6233863298f79016 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 26 May 2022 09:32:33 +0100 Subject: 50286: avoid zed error if nounset is in effect --- ChangeLog | 4 ++++ Functions/Misc/zed | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 3fbd9d9b5..6b65e7996 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-05-26 Peter Stephenson + + * 50286: Functions/Misc/zed: avoid error if nounset is in effect. + 2022-05-25 Norbert Lange * github #94: Completion/Linux/Command/_modutils: Support .zst diff --git a/Functions/Misc/zed b/Functions/Misc/zed index 7d0d590db..bb075512c 100644 --- a/Functions/Misc/zed +++ b/Functions/Misc/zed @@ -14,15 +14,17 @@ local var opts zed_file_name integer TMOUT=0 okargs=1 fun hist bind local -a expand -zparseopts -D -A opts f h b x: +zparseopts -D -A opts f h b x: || return 1 fun=$+opts[-f] hist=$+opts[-h] bind=$+opts[-b] -if [[ $opts[-x] == <-> ]]; then - expand=(-x $opts[-x]) -elif (( $+opts[-x] )); then - print -r "Integer expected after -x: $opts[-x]" >&2 - return 1 +if (( $+opts[-x] )); then + if [[ $opts[-x] == <-> ]]; then + expand=(-x $opts[-x]) + else + print -r "Integer expected after -x: $opts[-x]" >&2 + return 1 + fi fi [[ $0 = fned ]] && fun=1 -- cgit v1.2.3 From a99f96797f5fc424554a94313dfc0d4a5b0923a1 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 4 Jun 2022 14:19:42 -0700 Subject: 50323: create helper for shadowing builtins or existing functions and use it when redefining compadd et al. --- ChangeLog | 7 ++++ Completion/Base/Utility/_shadow | 71 +++++++++++++++++++++++++++++++++++ Completion/Base/Widget/_complete_help | 3 +- Functions/Zle/keeper | 3 +- 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 Completion/Base/Utility/_shadow (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 839beb4f9..5490385f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2022-06-04 Bart Schaefer + + * 50323: Completion/Base/Utility/_shadow (new file), + Completion/Base/Widget/_complete_help, Functions/Zle/keeper: + create helper for shadowing builtins or existing functions and + use it when redefining compadd et al. + 2022-06-03 Jun-ichi Takimoto * 50306: Src/jobs.c, Src/signals.c, Test/A05execution.ztst: fix diff --git a/Completion/Base/Utility/_shadow b/Completion/Base/Utility/_shadow new file mode 100644 index 000000000..5b0f79c36 --- /dev/null +++ b/Completion/Base/Utility/_shadow @@ -0,0 +1,71 @@ +#autoload + +## Recommended usage: +# { +# _shadow fname +# function fname { +# # Do your new thing +# } +# # Invoke callers of fname +# } always { +# _unshadow fname +# } +## Alternate usage: +# { +# _shadow -s suffix fname +# function fname { +# # Do other stuff +# fname@suffix new args for fname +# } +# # Invoke callers of fname +# } always { +# _unshadow -s suffix fname +# } +## + +# BUGS: +# * `functions -c` acts like `autoload +X` +# * name collisions are possible in alternate usage +# * functions that examine $0 probably misfire + +zmodload zsh/parameter # Or what? + +# This probably never comes up, but protect ourself from recursive call +# chains that may duplicate the top elements of $funcstack by creating +# a counter of _shadow calls and using it to make shadow names unique. +typeset -gHi _shadowdepth=0 + +# Create a copy of each fname so that a caller may redefine +_shadow() { + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((_shadowdepth+1)) ) + local fname + zparseopts -K -A fsfx -D s: + for fname; do + local shadowname=${fname}@${fsfx[-s]} + (( ${+functions[$fname]} )) && + builtin functions -c $fname $shadowname + done + ((_shadowdepth++)) +} + +# Remove the redefined function and shadowing name +_unshadow() { + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:${_shadowdepth} ) + local fname + zparseopts -K -A fsfx -D s: + for fname; do + local shadowname=${fname}@${fsfx[-s]} + if (( ${+functions[$shadowname]} )); then + builtin functions -c $shadowname $fname + builtin unfunction $shadowname + elif (( ${+functions[$fname]} )); then + builtin unfunction $fname + fi + done + ((_shadowdepth--)) +} + +# This is tricky. When we call _shadow recursively from autoload, +# there's an extra level of stack in $functrace that will confuse +# the later call to _unshadow. Fool ourself into working correctly. +(( ARGC )) && _shadow -s ${funcstack[2]}:${functrace[2]}:1 "$@" diff --git a/Completion/Base/Widget/_complete_help b/Completion/Base/Widget/_complete_help index 69855de9d..da5947e7f 100644 --- a/Completion/Base/Widget/_complete_help +++ b/Completion/Base/Widget/_complete_help @@ -10,6 +10,7 @@ _complete_help() { local -H _help_filter_funcstack="alternative|call_function|describe|dispatch|wanted|requested|all_labels|next_label" { + _shadow compadd compcall zstyle compadd() { return 1 } compcall() { _help_sort_tags use-compctl } zstyle() { @@ -43,7 +44,7 @@ _complete_help() { ${1:-_main_complete} } always { - unfunction compadd compcall zstyle + _unshadow compadd compcall zstyle } for i in "${(@ok)help_funcs}"; do diff --git a/Functions/Zle/keeper b/Functions/Zle/keeper index a40125771..1570eb94a 100644 --- a/Functions/Zle/keeper +++ b/Functions/Zle/keeper @@ -73,6 +73,7 @@ zstyle ':completion:expand-kept-result:*' completer _insert_kept _expand_word_and_keep() { { + _shadow compadd function compadd { local -A args zparseopts -E -A args J: @@ -85,7 +86,7 @@ _expand_word_and_keep() { } _expand_word } always { - unfunction compadd + _unshadow compadd } } -- cgit v1.2.3 From 52761c94185f8405d8069c1d4bacc8b5210a1850 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Wed, 8 Jun 2022 20:41:24 -0700 Subject: 50335: simplify "wait" usage, fix signal handling - remove the preliminary "wait" for all the process - remove "nomonitor" (because it was only needed for that "wait") - explicitly adds traps to exit for tty-generated signals plus TERM - capture the signal trap context and restore it in background jobs - wrap in an "always" block to clean up local helper functions - update comments to note another buglet and drop support for zsh 4.x. --- ChangeLog | 5 +++++ Functions/Misc/zargs | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 10 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 71f879776..c13d8a163 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-06-08 Bart Schaefer + + * 50335: Functions/Misc/zargs: simplify "wait" usage, fix signal + handling for functions used as the command. + 2022-06-07 Peter Stephenson * 50339: Doc/Zsh/options.yo, Src/text.c, Test/C04funcdef.ztst: diff --git a/Functions/Misc/zargs b/Functions/Misc/zargs index 81916a3ac..782d6811e 100644 --- a/Functions/Misc/zargs +++ b/Functions/Misc/zargs @@ -39,9 +39,14 @@ # # "Killed by a signal" is determined by the usual shell rule that $? is # the signal number plus 128, so zargs can be fooled by a command that -# explicitly exits with 129+. Also, zsh prior to 4.1.x returns 1 rather -# than 127 for "command not found" so this function incorrectly returns -# 123 in that case if used with zsh 4.0.x. +# explicitly exits with 129+. If the command passed to zargs is a shell +# function which uses "exit" instead of "return", zsh interprets 129+ as +# a signal sent to the process group and may terminate zargs with that +# status. This is avoided when running zargs -P 2 or greater. +# +# ZARGS_VERSION 1.5 is the last to support zsh 4.x. Also, zsh prior to +# 4.1.x returns 1 rather than 127 for "command not found" so zargs +# incorrectly returned 123 in that case if used with zsh 4.0.x. # # Because of "wait" limitations, --max-procs spawns max-procs jobs, then # waits for all of those, then spawns another batch, etc. @@ -71,6 +76,10 @@ # * The use of SIGUSR1 and SIGUSR2 to change the number of parallel jobs # is not supported. +{ # Begin "always" block to reset locally defined functions + +local ZARGS_VERSION="1.8" + # First, capture the current setopts as "sticky emulation" if zmodload zsh/parameter then @@ -84,11 +93,20 @@ else emulate $(emulate -l) -c '_zarun() { eval "$@" }' fi +local _zaTRAPS="$(trap)" +_zatraps() { + # In children, these traps may be reset to default behavior, even + # if the calling shell has traps. Restore to surrounding context, + # but assure that if zargs itself is signaled, children will exit. + [[ -o interactive ]] && + function TRAP{HUP,INT,QUIT,TERM} { exit $((128 + $1)) } + [[ -n "$_zaTRAPS" ]] && eval "$_zaTRAPS" + unset _zaTRAPS +} + emulate -L zsh || return 1 local -a opts eof n s l P i -local ZARGS_VERSION="1.7" - if zparseopts -a opts -D -- \ -eof::=eof e::=eof \ -exit x \ @@ -193,14 +211,14 @@ then (( c = $#command - 1 )) else command=( print -r -- ) fi -local wait bg -local execute=' +local bg execute=' if (( $opts[(I)-(-interactive|p)] )) then read -q "?$call?..." || continue elif (( $opts[(I)-(-verbose|t)] )) then print -u2 -r -- "$call" fi _zarun "{ + _zatraps \"\${call[@]}\" } $bg"' local ret=0 analyze=' @@ -263,12 +281,10 @@ fi if (( P != 1 && ARGC > 1 )) then - # These setopts are necessary for "wait" on multiple jobs to work. - setopt nonotify nomonitor + setopt nonotify # Do not report each exiting job local -a _zajobs local j bg='& _zajobs+=( $! )' - wait='wait' analyze=' for j in $_zajobs; do wait $j @@ -316,4 +332,8 @@ return $ret ) +} always { + builtin unfunction _zarun _zatraps +} + # } -- cgit v1.2.3 From 6e827d8f9a50653aa1905d8aff8cc91e6e2423c4 Mon Sep 17 00:00:00 2001 From: Julian Prein Date: Mon, 19 Sep 2022 02:02:18 +0000 Subject: 50648: Use $ZCALC_HISTORY where appropriate --- ChangeLog | 5 +++++ Doc/Zsh/contrib.yo | 7 +++++-- Functions/Misc/zcalc | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 375172ec9..48c65d01b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-09-25 Peter Stephenson + + * 50648: Functions/Misc/zcalc: Julian Prein: Use ZCALC_HISTFILE + where defined for zcalc history. + 2022-09-21 Jun-ichi Takimoto * Nicholas Vinson: 50641: aczsh.m4, configure.ac: use 'int main()' diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 0ef59dbc9..96de5aa9b 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -3972,8 +3972,11 @@ calculation is stored. For example, the result of the calculation on the line preceded by `tt(4> )' is available as tt($4). The last value calculated is available as tt(ans). Full command line editing, including the history of previous calculations, is available; the history is saved in -the file tt(~/.zcalc_history). To exit, enter a blank line or type `tt(:q)' -on its own (`tt(q)' is allowed for historical compatibility). +the file tt($ZCALC_HISTFILE). If tt($ZCALC_HISTFILE) is unset, +tt($ZDOTDIR/.zcalc_history) is used instead, which in turn falls backs to +tt($HOME/.zcalc_history) if tt($ZDOTDIR) is unset. To exit, enter a blank +line or type `tt(:q)' on its own (`tt(q)' is allowed for historical +compatibility). A line ending with a single backslash is treated in the same fashion as it is in command line editing: the backslash is removed, the diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc index 480373345..6cd2822c9 100644 --- a/Functions/Misc/zcalc +++ b/Functions/Misc/zcalc @@ -124,8 +124,10 @@ integer _rpn_mode _matched _show_stack _i _n integer _max_stack _push local -a _expressions stack + # We use our own history file with an automatic pop on exit. -history -ap "${ZDOTDIR:-$HOME}/.zcalc_history" +history -ap "${ZCALC_HISTFILE:-${ZDOTDIR:-$HOME}/.zcalc_history}" + _forms=( '%2$g' '%.*g' '%.*f' '%.*E' '') -- cgit v1.2.3 From b82e8e10355aba96cf3cf4e75bae71a6a3f8b235 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 17 Oct 2022 16:21:01 +0100 Subject: 50786: Make match etc. local when used in styles. Avoids side effects of add-zle-hook-widget. --- ChangeLog | 5 +++++ Functions/Misc/add-zle-hook-widget | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index cb47acd1b..61390fc9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-10-17 Peter Stephenson + + * 50786: Functions/Misc/add-zle-hook-widget: make match + etc. local when used in styles. + 2022-10-17 Jun-ichi Takimoto * Wesley Schwengle: 50736: Src/Zle/compmatch.c: silence diff --git a/Functions/Misc/add-zle-hook-widget b/Functions/Misc/add-zle-hook-widget index 4d8049083..4293a07dd 100644 --- a/Functions/Misc/add-zle-hook-widget +++ b/Functions/Misc/add-zle-hook-widget @@ -39,7 +39,7 @@ zstyle zle-hook types ${hooktypes#zle-} # Relying on multifuncdef option here function azhw:${^hooktypes} { - local -a hook_widgets + local -a hook_widgets match mbegin mend local hook # Values of these styles look like number:name # and we run them in number order @@ -58,7 +58,7 @@ function azhw:${^hooktypes} { # Redefine ourself with the setup left out function add-zle-hook-widget { - local -a hooktypes + local -a hooktypes match mbegin mend zstyle -a zle-hook types hooktypes # This part copied from add-zsh-hook -- cgit v1.2.3 From f9bb03cd72cdfe878e6ef51ef292c3a6b2550b7d Mon Sep 17 00:00:00 2001 From: Atte Peltomäki Date: Tue, 6 Dec 2022 20:40:21 -0800 Subject: 51088: fix standards reference in comment --- ChangeLog | 4 ++++ Functions/Misc/colors | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 8caeecd81..5e710bb7c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-12-06 Bart Schaefer + + * Atte Peltomäki: 51088: Functions/Misc/colors: typo in comment + 2022-12-03 Bart Schaefer * Philippe Altherr: 51094: Src/exec.c, Src/loop.c: consistent diff --git a/Functions/Misc/colors b/Functions/Misc/colors index 5c9924adb..8a0cec383 100644 --- a/Functions/Misc/colors +++ b/Functions/Misc/colors @@ -44,7 +44,7 @@ color=( 35 magenta 45 bg-magenta 36 cyan 46 bg-cyan 37 white 47 bg-white -# 38 iso-8316-6 # 48 bg-iso-8316-6 +# 38 iso-8613-6 # 48 bg-iso-8613-6 39 default 49 bg-default # Other codes: -- cgit v1.2.3 From ca7c42e1ee1706f39bbeb163ef323c819aee8357 Mon Sep 17 00:00:00 2001 From: Peter Grayson Date: Thu, 8 Dec 2022 09:52:42 -0500 Subject: 51138: Updated StGit patch detection in vcs_info The vcs_info patch detection code attempted to interrogate StGit patch stack state by inspecting .git/patches/applied and .git/patches/unapplied. As of StGit 0.15 (2009), patch stack metadata is captured in the repo's object database. And as of StGit 1.0 (2021), no stack or patch state is maintained in any files in the .git/ directory. Zsh's approach for interrogating StGit patch state is thus obsoleted. This patch updates vcs_info to determine whether StGit is initialized on a branch by looking at the appropriate git refs and uses StGit's prescribed interface for interrogating applied and unapplied patch state via the `stg series` command. This approach will work with all versions of StGit >=0.15. Signed-off-by: Peter Grayson --- ChangeLog | 5 ++++ Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 36 +++++++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index f3d5fde9d..63e9c5041 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-12-08 Peter Grayson + + * 51138: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: + Updated StGit patch detection in vcs_info + 2022-12-06 Bart Schaefer * Shohei YOSHIDA: 51108: Completion/Unix/Command/_nkf: single diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index e45eebc8e..23d4d31a1 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -184,15 +184,8 @@ fi VCS_INFO_adjust VCS_INFO_git_getaction ${gitdir} -local patchdir=${gitdir}/patches/${gitbranch} -if [[ -d $patchdir ]] && [[ -f $patchdir/applied ]] \ - && [[ -f $patchdir/unapplied ]] -then - # stgit - git_patches_applied=(${(f)"$(< "${patchdir}/applied")"}) - git_patches_unapplied=(${(f)"$(< "${patchdir}/unapplied")"}) - VCS_INFO_git_handle_patches -elif [[ -d "${gitdir}/rebase-merge" ]]; then +local patchdir +if [[ -d "${gitdir}/rebase-merge" ]]; then # 'git rebase -i' patchdir="${gitdir}/rebase-merge" local p @@ -389,6 +382,31 @@ elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then git_patches_unapplied=() fi VCS_INFO_git_handle_patches +elif command -v stg >/dev/null && + ${vcs_comm[cmd]} show-ref --quiet refs/stacks/${gitbranch} refs/heads/${gitbranch}.stgit 2>/dev/null && + git_patches_applied=(${(f)"$(stg series --noprefix --applied 2>/dev/null)"}) +then + # Testing for StGit patches is done after testing for all git-proper + # patches/states. If a StGit user's repo is in one of those states, they + # will want to see that instead of the StGit patch info. + + # Performance note: testing for the stg executable is done first because it + # is extremely cheap and there is nothing else to do if it isn't present. + # Using git to test whether a StGit stack is initialized is cheaper than + # running stg itself; especially for versions of StGit <= 2.0. Thus getting + # StGit patch info should only have a material runtime cost if StGit is + # installed and in-use for the current branch. + + # In StGit >=1.2, the existence of refs/stacks/ indicates StGit is + # initialized. In StGit >=0.15, it is refs/heads/.stgit. + + # N.B. the "--noprefix" option is available in StGit 2.x as an alias for + # --no-prefix. The former is compatible with StGit versions going back to + # 2008. + if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied; then + git_patches_unapplied=(${(f)"$(stg series --noprefix --unapplied 2>/dev/null)"}) + fi + VCS_INFO_git_handle_patches else gitmisc='' fi -- cgit v1.2.3 From 7cdada166cd9a05103a838d18e9be9811f68bc1d Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 8 Dec 2022 21:59:25 +0000 Subject: 51142: vcs_info git: Check the get-unapplied style as documented The style was treated as "always true" rather than as "settable, false by default" in the rebase-merge and cherry-pick cases. This affects the gen-unapplied-string hook, and may also affect gen-applied-string and set-patch-format hooks if they accessed VCS_INFO_get_data_git's internal parameters directly. If this affects you, just set the style in your zshrc: . zstyle ':vcs_info:git*:*:*' get-unapplied true --- ChangeLog | 5 +++++ Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 63e9c5041..dab0a9147 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-12-08 Daniel Shahaf + + * 51142: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: + vcs_info git: Check the get-unapplied style as documented + 2022-12-08 Peter Grayson * 51138: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index 23d4d31a1..37cd048db 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -244,7 +244,9 @@ if [[ -d "${gitdir}/rebase-merge" ]]; then (( $+REPLY )) && git_patches_applied+=( "$REPLY" ) done fi - if [[ -f "${patchdir}/git-rebase-todo" ]] ; then + if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied && + [[ -f "${patchdir}/git-rebase-todo" ]] + then for p in ${(f)"$(< "${patchdir}/git-rebase-todo")"}; do VCS_INFO_git_map_rebase_line_to_hash_and_subject "$p" (( $+REPLY )) && git_patches_unapplied+=( "$REPLY" ) @@ -374,7 +376,9 @@ elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then # TODO: maybe read up to the first blank line IFS='' read -r subject < "${gitdir}/MERGE_MSG" git_patches_applied=( "$(<${gitdir}/CHERRY_PICK_HEAD) ${subject}" ) - if [[ -f "${gitdir}/sequencer/todo" ]]; then + if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied && + [[ -f "${gitdir}/sequencer/todo" ]] + then # Get the next patches, and remove the one that's in CHERRY_PICK_HEAD. git_patches_unapplied=( ${${(M)${(f)"$(<"${gitdir}/sequencer/todo")"}:#pick *}#pick } ) git_patches_unapplied[1]=() -- cgit v1.2.3 From 510df60dd1f90f99026ac17e341df2313e064509 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 9 Dec 2022 01:39:21 +0000 Subject: 51144, 51146: vcs_info git: stg: Extract patch descriptions Joint work with Peter Grayson. --- ChangeLog | 6 ++++++ Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index dab0a9147..77dfc0377 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2022-12-09 Daniel Shahaf + + * 51144, 51146: + Functions/VCS_Info/Backends/VCS_INFO_get_data_git: vcs_info git: + stg: Extract patch descriptions + 2022-12-08 Daniel Shahaf * 51142: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index 37cd048db..9a608adab 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -388,7 +388,7 @@ elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then VCS_INFO_git_handle_patches elif command -v stg >/dev/null && ${vcs_comm[cmd]} show-ref --quiet refs/stacks/${gitbranch} refs/heads/${gitbranch}.stgit 2>/dev/null && - git_patches_applied=(${(f)"$(stg series --noprefix --applied 2>/dev/null)"}) + git_patches_applied=(${${(f)"$(stg series --noprefix --applied --description 2>/dev/null)"}/ #[#]}) then # Testing for StGit patches is done after testing for all git-proper # patches/states. If a StGit user's repo is in one of those states, they @@ -408,7 +408,7 @@ then # --no-prefix. The former is compatible with StGit versions going back to # 2008. if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied; then - git_patches_unapplied=(${(f)"$(stg series --noprefix --unapplied 2>/dev/null)"}) + git_patches_unapplied=(${${(f)"$(stg series --noprefix --unapplied --description 2>/dev/null)"}/ #[#]}) fi VCS_INFO_git_handle_patches else -- cgit v1.2.3 From dd13048b3b8cf710f44424ce9fedc2b56c31fde3 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Mon, 13 Mar 2023 19:46:39 -0700 Subject: 51572: fix "shift" error when running standalone --- ChangeLog | 2 ++ Functions/Misc/run-help | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index e80b09833..7ecc36a67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2023-03-13 Bart Schaefer + * 51572: Functions/Misc/run-help: fix error when running standalone + * Sven Joachim: 51563: Completion/Debian/Command/_sbuild: unmatched " 2023-03-11 Bart Schaefer diff --git a/Functions/Misc/run-help b/Functions/Misc/run-help index d52c1b032..14d09bd65 100644 --- a/Functions/Misc/run-help +++ b/Functions/Misc/run-help @@ -98,13 +98,13 @@ do if whence "run-help-$1:t" >/dev/null then local cmd_args - builtin getln cmd_args + builtin getln cmd_args && builtin print -z "$cmd_args" - cmd_args=( ${(z)cmd_args} ) + cmd_args=( ${(z)${cmd_args:-"$*"}} ) # Discard the command itself & everything before it. shift $cmd_args[(i)${run_help_orig_cmd:-$1}] cmd_args || - return + continue # Discard options, parameter assignments & paths. cmd_args=( ${cmd_args[@]:#([-+]*|*=*|*/*|\~*)} ) -- cgit v1.2.3 From b2421219836d571b4f0ffa9568740922fa7005b8 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Wed, 10 May 2023 21:17:51 -0700 Subject: 51593: improve search for command name after skipping prefix assignments This is aimed mostly at use of run-help as a standalone function rather than as a widget. When run-help is invoked outside widget context, there's no source line to search for the original command name, so this attempts searching the arguments. --- ChangeLog | 5 +++++ Functions/Misc/run-help | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index e7e84a04b..956cb7eeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2023-05-10 Bart Schaefer + + * 51593: Functions/Misc/run-help: improve search for original + command name after skipping prefix assignments + 2023-05-08 Jun-ichi Takimoto * 51692: Test/C02cond.ztst: do not skip tests for [[ -r file ]] diff --git a/Functions/Misc/run-help b/Functions/Misc/run-help index 14d09bd65..462044b72 100644 --- a/Functions/Misc/run-help +++ b/Functions/Misc/run-help @@ -58,11 +58,11 @@ do case $what in (*( is an alias for (noglob|nocorrect))*) [[ ${what[(w)7]:t} != ${what[(w)1]} ]] && - run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)7]:t} + run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)7]:t} ${(z)${what[(w)8,-1]}} ;; (*( is an alias)*) [[ ${what[(w)6]:t} != ${what[(w)1]} ]] && - run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)6]:t} + run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)6]:t} ${(z)${what[(w)7,-1]}} ;; (*( is a * function)) case ${what[(w)1]} in @@ -103,7 +103,7 @@ do cmd_args=( ${(z)${cmd_args:-"$*"}} ) # Discard the command itself & everything before it. - shift $cmd_args[(i)${run_help_orig_cmd:-$1}] cmd_args || + shift $cmd_args[(i)(${run_help_orig_cmd}|$1)] cmd_args 2>/dev/null || continue # Discard options, parameter assignments & paths. -- cgit v1.2.3 From 4f6a1b3717bb84b8243b13c4ec9171945893c934 Mon Sep 17 00:00:00 2001 From: Stephane Chazelas Date: Thu, 22 Jun 2023 12:52:12 -0700 Subject: 51813: differentiate empty $2 from omitted $2 in version comparisons --- ChangeLog | 7 ++++++- Functions/Misc/is-at-least | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index e89ffee1b..fc3818213 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2023-06-22 Bart Schaefer + + * Stephane: 51813: Functions/Misc/is-at-least: differentiate empty + $2 from omitted $2 to avoid wrong comparisons against ZSH_VERSION. + 2023-06-20 Jun-ichi Takimoto * 51877: Src/Modules/pcre.mdd, configure.ac: do not build pcre @@ -17,7 +22,7 @@ 2023-06-06 Peter Stephenson - * Stephan: 51818: Protect another ':'. + * Stephane: 51818: Protect another ':'. * Stephane: 51817: Protect some use of ':' from history modifier interpreation. diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least index d4ff3552a..5985684be 100644 --- a/Functions/Misc/is-at-least +++ b/Functions/Misc/is-at-least @@ -24,8 +24,14 @@ emulate -L zsh local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version order +: ${2=$ZSH_VERSION} + +# sort out the easy corner cases first +[[ $1 = $2 ]] && return 0 # same version +[[ -n $2 ]] || return 1 # no version + min_ver=(${=1}) -version=(${=2:-$ZSH_VERSION} 0) +version=(${=2} 0) while (( $min_cnt <= ${#min_ver} )); do while [[ "$part" != <-> ]]; do -- cgit v1.2.3 From 2a854aae481e7eb064729db28a71ed0efb2f33e6 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sun, 27 Aug 2023 15:22:14 -0700 Subject: 52028: improvements to _shadow / _unshadow, plus helper and doc --- ChangeLog | 4 +++ Completion/Base/Utility/_shadow | 66 ++++++++++++++++++++++++++++------------- Doc/Zsh/compsys.yo | 53 +++++++++++++++++++-------------- Doc/Zsh/contrib.yo | 21 +++++++++++++ Functions/Misc/mkshadow | 11 +++++++ 5 files changed, 112 insertions(+), 43 deletions(-) create mode 100644 Functions/Misc/mkshadow (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index bb6afe127..412dbda61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2023-08-27 Bart Schaefer + * 52028: Completion/Base/Utility/_shadow, Doc/Zsh/compsys.yo, + Doc/Zsh/contrib.yo, Functions/Misc/mkshadow: improve _shadow + and _unshadow, add helper function and update documentation + * Robert Woods: 52053: Src/utils.c: whitelist capability CAP_WAKE_ALARM in 'privasserted' function diff --git a/Completion/Base/Utility/_shadow b/Completion/Base/Utility/_shadow index 5b0f79c36..b5a8acb24 100644 --- a/Completion/Base/Utility/_shadow +++ b/Completion/Base/Utility/_shadow @@ -8,7 +8,7 @@ # } # # Invoke callers of fname # } always { -# _unshadow fname +# _unshadow # } ## Alternate usage: # { @@ -19,7 +19,7 @@ # } # # Invoke callers of fname # } always { -# _unshadow -s suffix fname +# _unshadow # } ## @@ -33,36 +33,62 @@ zmodload zsh/parameter # Or what? # This probably never comes up, but protect ourself from recursive call # chains that may duplicate the top elements of $funcstack by creating # a counter of _shadow calls and using it to make shadow names unique. -typeset -gHi _shadowdepth=0 +builtin typeset -gHi .shadow.depth=0 +builtin typeset -gHa .shadow.stack # Create a copy of each fname so that a caller may redefine _shadow() { - local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((_shadowdepth+1)) ) - local fname + emulate -L zsh + local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:$((.shadow.depth+1)) ) + local fname shadowname + local -a fnames zparseopts -K -A fsfx -D s: for fname; do - local shadowname=${fname}@${fsfx[-s]} - (( ${+functions[$fname]} )) && - builtin functions -c $fname $shadowname + shadowname=${fname}@${fsfx[-s]} + if (( ${+functions[$shadowname]} )) + then + # Called again with the same -s, just ignore it + continue + elif (( ${+functions[$fname]} )) + then + builtin functions -c -- $fname $shadowname + fnames+=(f@$fname) + elif (( ${+builtins[$fname]} )) + then + eval "function -- $shadowname { builtin $fname \"\$@\" }" + fnames+=(b@$fname) + else + eval "function -- $shadowname { command $fname \"\$@\" }" + fnames+=(c@$fname) + fi done - ((_shadowdepth++)) + [[ -z $REPLY ]] && REPLY=${fsfx[-s]} + builtin set -A .shadow.stack ${fsfx[-s]} $fnames -- ${.shadow.stack} + ((.shadow.depth++)) } # Remove the redefined function and shadowing name _unshadow() { - local -A fsfx=( -s ${funcstack[2]}:${functrace[2]}:${_shadowdepth} ) - local fname - zparseopts -K -A fsfx -D s: - for fname; do - local shadowname=${fname}@${fsfx[-s]} - if (( ${+functions[$shadowname]} )); then - builtin functions -c $shadowname $fname - builtin unfunction $shadowname - elif (( ${+functions[$fname]} )); then - builtin unfunction $fname + emulate -L zsh + local fname shadowname fsfx=${.shadow.stack[1]} + local -a fnames + [[ -n $fsfx ]] || return 1 + shift .shadow.stack + while [[ ${.shadow.stack[1]?no shadows} != -- ]]; do + fname=${.shadow.stack[1]#?@} + shadowname=${fname}@${fsfx} + if (( ${+functions[$fname]} )); then + builtin unfunction -- $fname fi + case ${.shadow.stack[1]} in + (f@*) builtin functions -c -- $shadowname $fname ;& + ([bc]@*) builtin unfunction -- $shadowname ;; + esac + shift .shadow.stack done - ((_shadowdepth--)) + [[ -z $REPLY ]] && REPLY=$fsfx + shift .shadow.stack + ((.shadow.depth--)) } # This is tricky. When we call _shadow recursively from autoload, diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 33baeab49..3f708eb5a 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -5229,13 +5229,12 @@ and hence is not normally called explicitly. ) findex(_shadow) findex(_unshadow) -xitem(tt(_shadow) [ tt(-s) var(suffix) ] var(command_name) ...) -item(tt(_unshadow) [ tt(-s) var(suffix) ] var(command_name) ...)( +xitem(tt(_shadow) [ tt(-s) var(suffix) ] [ -- ] var(command_name) ...) +item(tt(_unshadow))( The tt(_shadow) function creates a copy of each of the shell functions in the var(command_name) arguments. The original functions can then -be replaced by new implementations. A later call to tt(_unshadow), -with the same var(command_name) list, removes the new implementations, -if any, and restores the originals. +be replaced by new implementations. A later call to tt(_unshadow) +removes the new implementations, if any, and restores the originals. Recommended usage is to pair tt(_shadow) and tt(_unshadow) calls by use of an `tt(always)' block: @@ -5246,30 +5245,38 @@ example({ } # Invoke callers of fname } always { - _unshadow fname + _unshadow }) -Any var(command_name) may instead be a builtin, but in that case no -copy is created. The expectation is that an initial tt(_shadow) is -followed by creating a wrapper function, and therafter any nested or -recursive calls thus copy and replace the wrapper function. +The var(suffix), if supplied, is prepended by an `tt(@)' character and +then appended to each var(command_name) to create the copy. Thus +example(_shadow -s XX foo) +creates a function named `tt(foo@XX)'. This provides a well-known +name for the original implementation if the new implementation needs +to call it as a wrapper. If a nested call to tt(_shadow) uses the +same var(suffix), em(no new copy is made). The presumption thus is +that suffixes and new implementations correspond one to one. + +If var(command_name) is a builtin or external command, and there has been +no preceding tt(_shadow) replacement made, the function so created calls +the shadowed name prefixed by the tt(builtin) or tt(command) keywords as +appropriate. example({ - _shadow compadd - compadd LPAR()RPAR() { builtin compadd -O tmparr "$@" } + _shadow -s wrap compadd + compadd LPAR()RPAR() { + # compadd@wrap runs builtin compadd + compadd@wrap -O tmparr "$@" } } always { - _unshadow compadd + _unshadow }) -The var(suffix), if supplied, is prepended by an `tt(@)' character and -then appended to each var(command_name) to create the copy. Thus -example(_shadow -s XX foo) -creates a function named `tt(foo@XX)' (unless `tt(foo)' is a builtin). -Note that a nested call to tt(_shadow) with the same var(suffix) may -result in name collisions and unexpected results, but this provides a -well-known name for the original function if the new implementation -needs to call it as a wrapper. The same var(suffix) must be used in -the call to tt(_unshadow). When no var(suffix) is present, -tt(_shadow) creates a unique suffix to avoid name collisions. +When no var(suffix) argument is present, tt(_shadow) creates a unique +suffix to avoid name collisions. + +Arguments of tt(_unshadow) are ignored. Every listed var(command_name) +for the most recent call to tt(_shadow) is removed. This differs from +an early implementation that required tt(_unshadow) to receive the +same var(suffix) and var(command_name) list as tt(_shadow). ) findex(_store_cache) item(tt(_store_cache) var(cache_identifier) var(param) ...)( diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 96de5aa9b..ef11d77ad 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -4336,6 +4336,27 @@ example(is-at-least 3.1.6-15 && setopt NO_GLOBAL_RCS is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS is-at-least 2.6-17 || print "You can't use is-at-least here.") ) +findex(mkshadow) +findex(rmshadow) +xitem(tt(mkshadow) [ tt(-s) var(suffix) ] [ -- ] var(command_name) ...) +item(tt(rmshadow))( +These functions are an interface to the tt(_shadow) and tt(_unshadow) +completion utilities to make them more easily accessible in other +contexts. Usage is exactly as for the completion utility: +example({ + mkshadow fname + function fname { + # Do your new thing + } + # Invoke callers of fname +} always { + rmshadow +}) + +Upon return, the value of tt($REPLY) is the suffix used to create a +copy of the original var(command_name), so var(command_name)tt(@$REPLY) +invokes that original. +) findex(nslookup) item(tt(nslookup) [ var(arg) ... ])( This wrapper function for the tt(nslookup) command requires the diff --git a/Functions/Misc/mkshadow b/Functions/Misc/mkshadow new file mode 100644 index 000000000..2ae3a0f2c --- /dev/null +++ b/Functions/Misc/mkshadow @@ -0,0 +1,11 @@ +#autoload +# Front-end to the completion helper _shadow for use outside completion. +# This just forces proper autoload of _shadow/_unshadow and calls them. + +autoload _shadow +mkshadow() { unset REPLY; _shadow "$@" } +rmshadow() { unset REPLY; _unshadow } + +# Bootstrap because of autoload special case +unset REPLY +_shadow "$@" -- cgit v1.2.3 From f72757ccf30610fe8fdd1ed76d080971f767edaf Mon Sep 17 00:00:00 2001 From: Christoffer Lundell Date: Sat, 16 Sep 2023 20:06:12 -0700 Subject: 52082: Enable linewise edit-command when in visual-line mode. --- ChangeLog | 3 +++ Functions/Zle/edit-command-line | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 0390ea2b5..23e7ef6d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-09-16 Bart Schaefer + * Christoffer Lundell: 52082: Functions/Zle/edit-command-line: + Enable linewise edit-command when in visual-line mode. + * 52155: Test/D10nofork.ztst: Tests for non-forking substitution. * 52154: Doc/Zsh/expn.yo, Src/lex.c, Src/subst.c: implement diff --git a/Functions/Zle/edit-command-line b/Functions/Zle/edit-command-line index 5f7ea321f..d4b405eaf 100644 --- a/Functions/Zle/edit-command-line +++ b/Functions/Zle/edit-command-line @@ -11,15 +11,30 @@ local left right prebuffer buffer=$BUFFER lbuffer=$LBUFFER local TMPSUFFIX=.zsh # set up parameters depending on which context we are called from, # see below comment for more details -if (( REGION_ACTIVE )); then +if (( REGION_ACTIVE == 1 )); then if (( CURSOR < MARK )); then left=$CURSOR right=$MARK - lbuffer= else left=$MARK right=$CURSOR - lbuffer[right-left,-1]= fi - (( left++ )) + lbuffer=$lbuffer[++left,-1] + buffer=$BUFFER[left,++right] +elif (( REGION_ACTIVE == 2 )); then + local nl=$'\n' + if (( CURSOR < MARK )); then + left=${${BUFFER[1,CURSOR]}[(I)$nl]} + right=${${BUFFER[MARK+1,-1]}[(i)$nl]} + (( right += MARK )) + else + left=${${BUFFER[1,MARK]}[(I)$nl]} + right=${${BUFFER[CURSOR+1,-1]}[(i)$nl]} + (( right += CURSOR )) + fi + lbuffer=$lbuffer[++left,-1] + if [[ $BUFFER[right] = $nl ]]; then + # Keep the newline because "$(<$1)" below trims it + (( --right )) + fi buffer=$BUFFER[left,right] elif (( ! ZLE_RECURSIVE )); then prebuffer=$PREBUFFER -- cgit v1.2.3 From f093b41f09ab18459a75c86c0a896aa36432803b Mon Sep 17 00:00:00 2001 From: Jörg Sommer Date: Tue, 23 May 2023 18:25:41 +0200 Subject: 51776: run-help-openssl: Reduce code and use new manpages Openssl switches the naming of manpages to the common style openssl-$SUBCOMMAND, e.g. openssl-enc. For backward compatibility try to show the manpage with the old name if the new one doesn't exist. --- ChangeLog | 3 +++ Functions/Misc/run-help-openssl | 8 +------- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index f03fd0d5c..eeb4cd618 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-09-20 Oliver Kiddle + * Jörg Sommer: 51776: Functions/Misc/run-help-openssl: + Reduce code and use new manpages + * Wim de With: 51857: Completion/Linux/Command/_fusermount: Include fusermount3 in fusermount completions diff --git a/Functions/Misc/run-help-openssl b/Functions/Misc/run-help-openssl index c528418c8..e4e45070e 100644 --- a/Functions/Misc/run-help-openssl +++ b/Functions/Misc/run-help-openssl @@ -1,7 +1 @@ - -if [ $# -eq 0 ]; then - man openssl -else - man $1 -fi - +man openssl${1:+-$1} || man ${1:-openssl} -- cgit v1.2.3 From 9eb2b047035273891c66f6d0fc23edb22d6bfad5 Mon Sep 17 00:00:00 2001 From: Jörg Sommer Date: Thu, 18 May 2023 00:12:45 +0200 Subject: 51747: ip accepts the reduction of link to l. --- ChangeLog | 3 +++ Functions/Misc/run-help-ip | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index eeb4cd618..e12ed92e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-09-20 Oliver Kiddle + * Jörg Sommer: 51747: Functions/Misc/run-help-ip: + ip accepts the reduction of link to l + * Jörg Sommer: 51776: Functions/Misc/run-help-openssl: Reduce code and use new manpages diff --git a/Functions/Misc/run-help-ip b/Functions/Misc/run-help-ip index b811ce352..f635cce71 100644 --- a/Functions/Misc/run-help-ip +++ b/Functions/Misc/run-help-ip @@ -18,7 +18,7 @@ case $1 in (addrl*) man ip-addrlabel ;; (a*) man ip-address ;; (l2*) man ip-l2tp ;; - (li*) man ip-link ;; + (l*) man ip-link ;; (ma*) man ip-maddress ;; (mo*) man ip-monitor ;; (mr*) man ip-mroute ;; -- cgit v1.2.3 From 60479a7a180a837df4d973b5b9b50f4cd566bef9 Mon Sep 17 00:00:00 2001 From: Jörg Sommer Date: Wed, 31 May 2023 19:45:59 +0200 Subject: 51812: run-help for docker, perf, podman, ssh, svnadmin --- ChangeLog | 7 +++++++ Functions/Misc/run-help-docker | 9 +++++++++ Functions/Misc/run-help-perf | 1 + Functions/Misc/run-help-podman | 9 +++++++++ Functions/Misc/run-help-ssh | 6 ++++++ Functions/Misc/run-help-svnadmin | 1 + 6 files changed, 33 insertions(+) create mode 100644 Functions/Misc/run-help-docker create mode 100644 Functions/Misc/run-help-perf create mode 100644 Functions/Misc/run-help-podman create mode 100644 Functions/Misc/run-help-ssh create mode 100644 Functions/Misc/run-help-svnadmin (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index b7d49ace2..a54ffdfe2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2023-10-10 Oliver Kiddle + + * Jörg Sommer: 51812: Functions/Misc/run-help-docker, + Functions/Misc/run-help-perf, Functions/Misc/run-help-podman, + Functions/Misc/run-help-ssh, Functions/Misc/run-help-svnadmin: + run-help for docker, perf, podman, ssh, svnadmin + 2023-10-05 Bart Schaefer * 52204: Src/parse.c: fix unmeta() thinko from 52193 diff --git a/Functions/Misc/run-help-docker b/Functions/Misc/run-help-docker new file mode 100644 index 000000000..09a8a221a --- /dev/null +++ b/Functions/Misc/run-help-docker @@ -0,0 +1,9 @@ +if [[ $# == 0 ]] +then + man docker +elif [[ $# > 1 && $1 == (builder|checkpoint|config|container|context|image|manifest|network|node|plugin|secret|service|stack|swarm|system|trust|volume) ]] +then + man docker-$1-$2 +else + man docker-$1 +fi diff --git a/Functions/Misc/run-help-perf b/Functions/Misc/run-help-perf new file mode 100644 index 000000000..2e0695af2 --- /dev/null +++ b/Functions/Misc/run-help-perf @@ -0,0 +1 @@ +man perf${1:+-$1} diff --git a/Functions/Misc/run-help-podman b/Functions/Misc/run-help-podman new file mode 100644 index 000000000..64d9cd83f --- /dev/null +++ b/Functions/Misc/run-help-podman @@ -0,0 +1,9 @@ +if [[ $# == 0 ]] +then + man podman +elif [[ $# > 1 && $1 == (container|generate|healthcheck|image|kube|machine|manifest|network|pod|secret|system|volume) ]] +then + man podman-$1-$2 +else + man podman-$1 +fi diff --git a/Functions/Misc/run-help-ssh b/Functions/Misc/run-help-ssh new file mode 100644 index 000000000..9c48596ff --- /dev/null +++ b/Functions/Misc/run-help-ssh @@ -0,0 +1,6 @@ +if [[ $# < 2 ]] +then + man ssh +else + run-help $2 +fi diff --git a/Functions/Misc/run-help-svnadmin b/Functions/Misc/run-help-svnadmin new file mode 100644 index 000000000..dbddd6396 --- /dev/null +++ b/Functions/Misc/run-help-svnadmin @@ -0,0 +1 @@ +svnadmin help $1 | ${=PAGER:-more} -- cgit v1.2.3 From a920e368b87f24e95b015eb091e1112c378c2939 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Wed, 11 Oct 2023 00:37:35 +0200 Subject: unposted (cf. 52166): remove obsolete helper for svk --- ChangeLog | 3 +++ Functions/Misc/run-help-svk | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 Functions/Misc/run-help-svk (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index a54ffdfe2..3e9b6ffa0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-10-10 Oliver Kiddle + * unposted (cf. 52166): Functions/Misc/run-help-svk: + remove obsolete helper for svk + * Jörg Sommer: 51812: Functions/Misc/run-help-docker, Functions/Misc/run-help-perf, Functions/Misc/run-help-podman, Functions/Misc/run-help-ssh, Functions/Misc/run-help-svnadmin: diff --git a/Functions/Misc/run-help-svk b/Functions/Misc/run-help-svk deleted file mode 100644 index 782538246..000000000 --- a/Functions/Misc/run-help-svk +++ /dev/null @@ -1 +0,0 @@ -svk help $1 | ${=PAGER:-more} -- cgit v1.2.3 From d86cc841f78086b03fc22d2971ff82cdb3904d4d Mon Sep 17 00:00:00 2001 From: Sebastian Gniazdowski Date: Thu, 26 Oct 2023 13:41:03 -0700 Subject: 52240: use work-var $s not $suffix when setting flags --- ChangeLog | 3 +++ Functions/MIME/zsh-mime-handler | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index ebfd2731f..e67a33ea9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-10-25 Bart Schaefer + * Sebastian Gniazdowski: 52240: Functions/MIME/zsh-mime-handler: + use work-var $s not $suffix when setting flags + * 52244: Src/Modules/zutil.c, Src/Zle/compcore.c, Src/Zle/compresult.c, Src/builtin.c, Src/glob.c, Src/hist.c, Src/input.c, Src/params.c, Src/utils.c: Coverity defects 1547831, diff --git a/Functions/MIME/zsh-mime-handler b/Functions/MIME/zsh-mime-handler index 288a0796d..2feacf063 100644 --- a/Functions/MIME/zsh-mime-handler +++ b/Functions/MIME/zsh-mime-handler @@ -193,7 +193,7 @@ if ! zsh-mime-contexts -s $suffix flags flags; then # Same again for flags. s=$suffix while true; do - flags="${zsh_mime_flags[$suffix]}" + flags="${zsh_mime_flags[$s]}" if [[ -n $flags ]]; then break fi -- cgit v1.2.3 From 02a99863b0f9243479cdf9aae220c91cd8facae6 Mon Sep 17 00:00:00 2001 From: Sebastian Gniazdowski Date: Wed, 29 Nov 2023 15:28:56 -0800 Subject: 52145: Prompt theme with current time and abbreviated VCS_info. --- ChangeLog | 5 ++ Functions/Prompts/prompt_sprint2_setup | 128 +++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 Functions/Prompts/prompt_sprint2_setup (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 64155b175..892072370 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2023-11-29 Bart Schaefer + + * Sebastian Gniazdowski: 52145: Functions/Prompts/prompt_sprint2_setup: + Contributed prompt theme with current time and abbreviated VCS_info. + 2023-11-23 Bart Schaefer * 52325: Doc/Zsh/expn.yo, Doc/Zsh/mod_ksh93.yo, Doc/Zsh/params.yo: diff --git a/Functions/Prompts/prompt_sprint2_setup b/Functions/Prompts/prompt_sprint2_setup new file mode 100644 index 000000000..0eaea4473 --- /dev/null +++ b/Functions/Prompts/prompt_sprint2_setup @@ -0,0 +1,128 @@ +# Created by Sebastian Gniazdowski + +prompt_sprint2_help () { + cat < + +You can provide only N first arguments, N=1..5. + +The default colors are: 39 green blue green yellow +EOF +} + +prompt_sprint2_setup () { + local col_time_line=${1:-'39'} + local col_parens=${2:-'green'} + local col_text=${3:-'blue'} + local col_at_colon=${4:-'green'} + local col_prompt=${5:-'yellow'} + + autoload -Uz vcs_info + + typeset -gA _psvar + + local cl_time_line="%B%F{$col_time_line}" + local cl_text="%b%F{$col_text}" + local cl_parens="%B%F{$col_parens}" + local cl_at_colon="%b%F{$col_at_colon}" + local cl_prompt="%B%F{$col_prompt}" + local cl_rst="%b%f" + + local _lpar="${cl_parens}[" + local _rpar="${cl_parens}]" + + local _time="$cl_time_line%D{%H:%M}" + _psvar[user]='%n' + local _user="$cl_text"'${_psvar[user]}' + _psvar[at]="@" + _psvar[host]='%m' + local _at="$cl_at_colon"'${_psvar[at]}'"$cl_text"'${_psvar[host]}' + _psvar[colon]=':' + local _path="$cl_at_colon"'${_psvar[colon]}'"$cl_text%28<*<%/%<<" + local _line="$cl_time_line%i" + local _prompt="$cl_prompt# " + + # You can instantly shorten the prompt by setting PSSHORT=1 + if [[ "$COLUMNS" -le 94 || "$PSSHORT" = "1" ]]; then + _psvar=() + else + _psvar[user]='%n' + _psvar[at]="@" + _psvar[host]='%m' + _psvar[colon]=':' + fi + + PS1="$_time$_lpar$_user$_at$_path$_rpar$_line$_prompt$cl_rst" + + PS2="$cl_parens> $cl_rst" + + RPS1='${vcs_info_msg_0_}' + prompt_opts=(cr subst percent) + + zstyle ':vcs_info:*' enable git svn darcs bzr hg + zstyle ':vcs_info:*' stagedstr "%F{green}●$cl_rst" + zstyle ':vcs_info:*' unstagedstr "%F{yellow}●$cl_rst" + zstyle ':vcs_info:*' check-for-changes true + zstyle ':vcs_info:*' formats '(%s)-[%b%u%c]-' + + add-zsh-hook precmd prompt_sprint2_precmd +} + +prompt_sprint2_precmd () { + setopt localoptions noxtrace noksharrays + + # You can instantly shorten the prompt by setting PSSHORT=1 + if [[ "$COLUMNS" -le 94 || "$PSSHORT" = "1" ]]; then + _psvar=() + else + _psvar[user]='%n' + _psvar[at]="@" + _psvar[host]='%m' + _psvar[colon]=':' + fi + + local -a changed_files + changed_files=( ) + git diff --quiet 2>/dev/null || changed_files=( ${(f)"$( git diff --name-only 2>/dev/null )"} ) + changed_files=( $^changed_files(N) ) + if [[ "${#changed_files}" -gt 0 ]]; then + local basedir + basedir="$(git rev-parse --show-toplevel)/" + changed_files=( ${(f)"$( find "${basedir}${^changed_files[@]}" -mtime +2 )"} ) + fi + + if [[ "${#changed_files}" -eq 0 ]]; then + zstyle ':vcs_info:*' formats ' (%s)-[%b%u%c]' + else + zstyle ':vcs_info:*' formats ' (%s)-[%b%u%B%F{yellow}-OLD-%c%%b%f]' + fi + + vcs_info +} + +prompt_sprint2_preview () { + local -a colors_time_line colors_text + colors_time_line=(red yellow green blue magenta cyan) + colors_text=(red yellow green blue magenta cyan) + + local ctime_line ctext i j + + if (( ! $#* )); then + for (( i = 1; i <= ${#colors_time_line}; i++ )); do + ctime_line="${colors_time_line[$i]}" + for (( j = 1; j <= ${#colors_text}; j++ )); do + ctext="${colors_text[$j]}" + prompt_preview_theme sprint2 "$ctime_line" "red" "$ctext" + (( i != ${#colors_time_line} || j != ${#colors_text} )) && print + done + done + else + prompt_preview_theme sprint2 "$@" + fi +} + +prompt_sprint2_setup "$@" + +# vim:ft=zsh -- cgit v1.2.3 From d6e4ddd4d48b6ac9c0a29b95e0e2fc0e6012d725 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Fri, 5 Jan 2024 20:38:58 -0800 Subject: 52465: use NULL_GLOB when expanding zmv input pattern to avoid NOMATCH exit --- ChangeLog | 5 +++++ Doc/Zsh/contrib.yo | 8 ++++---- Functions/Misc/zmv | 8 +++++++- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index e7b785c7f..1c7e7786f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2024-01-05 Bart Schaefer + + * 52465: Doc/Zsh/contrib.yo, Functions/Misc/zmv: use NULL_GLOB + when expanding the input pattern to avoid NOMATCH exit + 2023-12-06 Jun-ichi Takimoto * 52413: Completion/Unix/Command/_iconv: support Citrus version diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index f43ac2257..e1781a5e1 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -4668,10 +4668,10 @@ renames `tt(foo.lis)' to `tt(foo.txt)', `tt(my.old.stuff.lis)' to The pattern is always treated as an tt(EXTENDED_GLOB) pattern. Any file whose name is not changed by the substitution is simply ignored. Any -error (a substitution resulted in an empty string, two substitutions gave -the same result, the destination was an existing regular file and tt(-f) -was not given) causes the entire function to abort without doing -anything. +error (no files matched the var(srcpat), substitution resulted in an empty +string, two substitutions gave the same result, the destination was an +existing regular file and tt(-f) was not given) causes the entire function +to abort without doing anything. In addition to pattern replacement, the variable tt($f) can be referred to in the second (replacement) argument. This makes it possible to diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv index 269fe5ba5..5c03e9ea1 100644 --- a/Functions/Misc/zmv +++ b/Functions/Misc/zmv @@ -236,12 +236,18 @@ if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then else fpat=$pat fi -files=(${~fpat}) [[ -n $hasglobqual ]] && pat=$opat errs=() +() { + # (#qN) breaks bareglobqual -Q option, so: + setopt localoptions nullglob + files=(${~fpat}) +} +(( ${#files} )) || errs=( "no files matched \`$fpat'" ) + for f in $files; do if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then # This looks like a recursive glob. This isn't good enough, -- cgit v1.2.3 From 2744208ab3eab1741157e01484d08095bd8ef528 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 3 Feb 2024 20:10:52 -0800 Subject: unposted: elaboration on Roman's "slurp" implementation from zsh-users --- ChangeLog | 3 +++ Functions/Misc/zslurp | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Functions/Misc/zslurp (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 386ef3ab9..238c12c16 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2024-02-03 Bart Schaefer + * unposted: cf. Roman in users/29472: Functions/Misc/zslurp: + Efficient lossless read of stdin into $REPLY + * unposted: Src/Zle/zle_tricky.c, Src/parse.c, Src/pattern.c: Record as comments some notes about namespace usage exceptions. diff --git a/Functions/Misc/zslurp b/Functions/Misc/zslurp new file mode 100644 index 000000000..84df0c948 --- /dev/null +++ b/Functions/Misc/zslurp @@ -0,0 +1,31 @@ +#!/bin/zsh -f + +# Read stdin verbatim and as efficiently as possible into $REPLY, +# stopping without any change to $REPLY in the event of any error. +# Benchmarked by Roman Perepelitsa in zsh-users/29472 + +# Although this function faithfully records the input stream, later +# references to $REPLY with the multibyte option back in effect will +# (re-)interpret the content as multibyte characters. This may not be +# what is desired. + +emulate -L zsh -o no_multibyte + +### Alternate formulation, faster on bigger files +# # /dev/fd/0 is treated specially by -f so also check /dev/fd +# if [[ -d /dev/fd && -f /dev/fd/0 ]] && zmodload zsh/mapfile +# then +# local +h -Ar mapfile +# typeset -g REPLY="${mapfile[/dev/fd/0]}" && return +# fi +# # else fall through to read from pipe/socket + +zmodload zsh/system || return +local -a content +local -i i=0 +while true; do + sysread 'content[++i]' && continue + (( $? == 5 )) || return + break +done +typeset -g REPLY=${(j::)content} -- cgit v1.2.3 From fb9a7cc5dd07910afa7ebea174b379350cae4c91 Mon Sep 17 00:00:00 2001 From: midchildan Date: Sat, 3 Feb 2024 01:28:00 +0900 Subject: 52520: add new features and improvements to the "incarg" ZLE widget - Decrement integers without defining a new widget - Preserve the number of leading zeros - Increment binaries, octals, and hexadecimals - Move the cursor to the end of the incremented integer - Create a sequence of integers across terminal panes - Add a Vim variant - Also add tests --- ChangeLog | 4 + Doc/Zsh/contrib.yo | 30 ++++- Functions/Zle/incarg | 273 ++++++++++++++++++++++++++++++++----- Test/X05zleincarg.ztst | 360 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 630 insertions(+), 37 deletions(-) create mode 100644 Test/X05zleincarg.ztst (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 36029a2a8..faae11c80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2024-02-15 Oliver Kiddle + * 52520: midchildan: Doc/Zsh/contrib.yo, Functions/Zle/incarg, + Test/X05zleincarg.ztst: add new features and improvements to the + "incarg" ZLE widget + * github #112: Poncho: Completion/Unix/Command/_todo.sh: Completion: todo.sh uses shorthelp and not showhelp diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index e1781a5e1..718686587 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2620,12 +2620,30 @@ 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(vim-), +the cursor will jump to the nearest integer after the cursor before incrementing +it. + +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(vim-) and tt(sync-) can be combined into tt(vim-sync-). example(bindkey '^X+' incarg) ) diff --git a/Functions/Zle/incarg b/Functions/Zle/incarg index cff0cfe4c..1131b148b 100644 --- a/Functions/Zle/incarg +++ b/Functions/Zle/incarg @@ -1,43 +1,254 @@ -# Shell function to increment an integer either under the cursor or just -# to the left of it. Use +emulate -L zsh + +# 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-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. +# +# Example Usage: +# # 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). +# 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 -emulate -L zsh -setopt extendedglob +setopt localoptions extended_glob +local match mbegin mend MATCH MBEGIN MEND i -local rrest lrest num +# find the number and determine the base +integer pos=$(( CURSOR + 1 )) base=0 -rrest=${RBUFFER##[0-9]#} -if [[ $RBUFFER = [0-9]* ]]; then - if [[ -z $rrest ]]; then - num=$RBUFFER - else - num=${RBUFFER[1,-$#rrest-1]} +# 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 -lrest=${LBUFFER%%[0-9]#} -if [[ $LBUFFER = *[0-9] ]]; then - if [[ -z $lrest ]]; then - num="$LBUFFER$num" +# 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 + +# 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 - num="${LBUFFER[$#lrest+1,-1]}$num" + zle -M "[$WIDGET] unsupported terminal" + return 1 + fi + (( delta *= pane_index )) +fi + +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 + +local raw_result padded +raw_result="$( \ + printf "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null)" +padded="${raw_result// /0}" + +integer oldnum="$base#$old" 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 + +BUFFER[first,last]="$new" -[[ -n $num ]] && (( num += ${NUMERIC:-${incarg:-1}} )) +integer offset=0 +if [[ "$WIDGET" == vi* ]]; then + offset=-1 +fi +(( CURSOR = last + $#BUFFER - oldlen + offset )) -BUFFER="$lrest$num$rrest" +return 0 diff --git a/Test/X05zleincarg.ztst b/Test/X05zleincarg.ztst new file mode 100644 index 000000000..2a6aa2d3f --- /dev/null +++ b/Test/X05zleincarg.ztst @@ -0,0 +1,360 @@ +# 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-}{,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 + unset TMUX_PANE ITERM_SESSION_ID + tmux() { + echo "$TMUX_PANE" + } + ' + +%test + + zletest $'0\C-n' +0:increment an integer with incarg +>BUFFER: 1 +>CURSOR: 1 + + zletest $'0\C-p' +0:decrement an integer with decarg +>BUFFER: -1 +>CURSOR: 2 + + zletest $'echo 0\e0\C-n' +0:increment an integer with vim-incarg +>BUFFER: echo 1 +>CURSOR: 5 + + zletest $'echo 0\e0\C-p' +0:decrement an integer with vim-decarg +>BUFFER: echo -1 +>CURSOR: 6 + + 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 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 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 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 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 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 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:tmux pane number takes precedence over iTerm2's +>BUFFER: 1 +>CURSOR: 1 + + zletest $'0\e2\C-n' +0:Providing a numeric argument will change the incremented amount +>BUFFER: 2 +>CURSOR: 0 + + zpty_run 'incarg=3' + zletest $'0\e\C-n' + zpty_run 'unset incarg' +0:Setting the incarg variable will change the default incremented amount +>BUFFER: 3 +>CURSOR: 0 + + zpty_run 'incarg=3' + zletest $'0\e2\C-n' + zpty_run 'unset incarg' +0:A numeric argument will take precedence over the incarg variable +>BUFFER: 2 +>CURSOR: 0 + + zpty_run 'TMUX_PANE=2' + zletest $'0\e2\C-f' + zpty_run 'unset TMUX_PANE' +0:Providing a numeric argument will work for the sync- variants of incarg +>BUFFER: 4 +>CURSOR: 0 + + zletest $'000\C-n' +0:Incrementing a decimal integer preserves leading zeros +>BUFFER: 001 +>CURSOR: 3 + + zletest $'-001\C-n\C-n' +0:Leading zeros are preserved when the digit turns from negative to positive +>BUFFER: 001 +>CURSOR: 3 + + zletest $'001\C-p\C-p' +0:Leading zeros are preserved when the digit turns from positive to negative +>BUFFER: -001 +>CURSOR: 4 + + zletest $'001\e1000\C-n' +0:Incrementing an integer works when the result has more zeros than the original +>BUFFER: 1001 +>CURSOR: 3 + + zletest $'001\e2000\C-p' +0:Decrementing an integer with leading zeros works when the result has more digits than the original +>BUFFER: -1999 +>CURSOR: 4 + + zletest $'0b11\C-n' +0:Increment a binary integer +>BUFFER: 0b100 +>CURSOR: 5 + + zletest $'0B11\C-n' +0:Increment a binary integer with an upper case prefix +>BUFFER: 0B100 +>CURSOR: 5 + + zletest $'0b100\C-p' +0:Decrement a binary integer +>BUFFER: 0b11 +>CURSOR: 4 + + zletest $'0b0011\C-n' +0:Increment a binary integer preserves leading zeros +>BUFFER: 0b0100 +>CURSOR: 6 + + zletest $'0b001\e8\C-n' +0:Incrementing a binary integer work when the result has more zeros than the original +>BUFFER: 0b1001 +>CURSOR: 5 + + zletest $'0b0\C-p' +0:Decrementing a binary integer to a negative value will fail +>BUFFER: 0b0 +>CURSOR: 3 + + zletest $'0o7\C-n' +0:Increment an octal integer +>BUFFER: 0o10 +>CURSOR: 4 + + zletest $'0O7\C-n' +0:Increment an octal integer with an upper case prefix +>BUFFER: 0O10 +>CURSOR: 4 + + zletest $'0o10\C-p' +0:Decrement an octal integer +>BUFFER: 0o7 +>CURSOR: 3 + + zletest $'0o0\C-p' +0:Decrementing an octal integer to a negative value will fail +>BUFFER: 0o0 +>CURSOR: 3 + + zletest $'0x9\C-n' +0:Increment a hexadecimal integer +>BUFFER: 0xa +>CURSOR: 3 + + zletest $'0X9\C-n' +0:Increment a hexadecimal integer with an upper case prefix +>BUFFER: 0XA +>CURSOR: 3 + + zletest $'0xf\C-n' +0:Increment a hexadecimal integer with no numeric digit +>BUFFER: 0x10 +>CURSOR: 4 + + zletest $'0x10\C-p' +0:Decrement a hexadecimal integer +>BUFFER: 0xf +>CURSOR: 3 + + zletest $'0x0\C-p' +0:Decrementing an octal integer to a negative value will fail +>BUFFER: 0x0 +>CURSOR: 3 + + zletest $'0x0b1\C-n' +0:a number that starts with 0x0b is interpreted as a hexadecimal integer +>BUFFER: 0x0b2 +>CURSOR: 5 + + zletest $'10x9\e0\C-n' +0:[0-9]0x[0-9a-f] will become [0-9]1x[0-9a-f] when incremented from the left of x +>BUFFER: 11x9 +>CURSOR: 1 + + zletest $'10x9\eFx\C-n' +0:[0-9]0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on x +>BUFFER: 10xa +>CURSOR: 3 + + zletest $'10x9\e\C-n' +0:[0-9]0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on the right of x +>BUFFER: 10xa +>CURSOR: 3 + + zletest $'10b1\e0\C-n' +0:[0-9]0b[01] will become [0-9]1b[01] when incremented from the left of b +>BUFFER: 11b1 +>CURSOR: 1 + + zletest $'10b1\eFb\C-n' +0:[0-9]0b[01] will increment the binary 0b[01] when the cursor is on b +>BUFFER: 10b10 +>CURSOR: 4 + + zletest $'10b1\e\C-n' +0:[0-9]0b[01] will increment the binary 0b[01] when the cursor is on the right of b +>BUFFER: 10b10 +>CURSOR: 4 + + zletest $'10o7\e0\C-n' +0:[0-9]0o[0-7] will become [0-9]1o[0-7] when incremented from the left of o +>BUFFER: 11o7 +>CURSOR: 1 + + zletest $'10o7\eFo\C-n' +0:[0-9]0o[0-7] will increment the octal 0o[0-7] when the cursor is on o +>BUFFER: 10o10 +>CURSOR: 4 + + zletest $'10o7\e\C-n' +0:[0-9]0o[0-7] will increment the octal 0o[0-7] when the cursor is on the right of o +>BUFFER: 10o10 +>CURSOR: 4 + + zletest $'0b0x9\eF0\C-n' +0:0b0x[0-9a-f] will increment the binary 0b0 when the cursor is on the left of x +>BUFFER: 0b1x9 +>CURSOR: 2 + + zletest $'0b0x9\eFx\C-n' +0:0b0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on top of x +>BUFFER: 0b0xa +>CURSOR: 4 + + zletest $'0b0x9\e\C-n' +0:0b0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on the right of x +>BUFFER: 0b0xa +>CURSOR: 4 + + 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 $'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 + +%clean + + zmodload -ui zsh/zpty -- cgit v1.2.3 From 74722b8d4ed20828950d396a523dcde1aa10b466 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Fri, 16 Feb 2024 08:42:42 +0100 Subject: 52546: incarg: avoid unneeded subshell --- ChangeLog | 4 ++++ Functions/Zle/incarg | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index faae11c80..e9bc0d9c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2024-02-16 Mikael Magnusson + + * 52546: Functions/Zle/incarg: incarg: avoid unneeded subshell + 2024-02-15 Oliver Kiddle * 52520: midchildan: Doc/Zsh/contrib.yo, Functions/Zle/incarg, diff --git a/Functions/Zle/incarg b/Functions/Zle/incarg index 1131b148b..9d56b21f6 100644 --- a/Functions/Zle/incarg +++ b/Functions/Zle/incarg @@ -214,8 +214,7 @@ case "$base" in esac local raw_result padded -raw_result="$( \ - printf "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null)" +printf -v raw_result "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null padded="${raw_result// /0}" integer oldnum="$base#$old" newnum="$base#$padded" 2> /dev/null -- cgit v1.2.3 From 36a2d5cfa49a6b7d699269cb4f22d5f3d0255bc8 Mon Sep 17 00:00:00 2001 From: midchildan Date: Thu, 29 Feb 2024 22:34:33 +0900 Subject: 52641: incarg: add a backward variant and make it repeatable --- ChangeLog | 5 + Doc/Zsh/contrib.yo | 8 +- Functions/Zle/incarg | 64 ++++++++- Test/X05zleincarg.ztst | 358 ++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 347 insertions(+), 88 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 9718d0cae..5c839cd19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2024-03-05 Oliver Kiddle + + * 52641: midchildan: Doc/Zsh/contrib.yo, Functions/Zle/incarg, + Test/X05zleincarg.ztst: add a backward variant and make it repeatable + 2024-03-02 Bart Schaefer * 52652: Src/params.c, Test/D04parameter.ztst: fix obscure bug diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index ea00f0ccc..e682c800a 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2635,7 +2635,8 @@ 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. +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 @@ -2643,8 +2644,9 @@ 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) and tt(sync-) can be combined, for example, into -tt(vim-sync-). In this case, the tt(vi) prefix should come first. +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 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 diff --git a/Test/X05zleincarg.ztst b/Test/X05zleincarg.ztst index 2a6aa2d3f..cd9817c82 100644 --- a/Test/X05zleincarg.ztst +++ b/Test/X05zleincarg.ztst @@ -10,7 +10,7 @@ fi zpty_run ' autoload -Uz incarg - for name in {,vim-}{,sync-}{inc,dec}arg; do + for name in {,vim-,vim-backward-}{,sync-}{inc,dec}arg; do zle -N "$name" incarg done bindkey -v "^N" incarg @@ -21,6 +21,8 @@ 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" @@ -29,26 +31,40 @@ %test +# Basic increment & decrement + zletest $'0\C-n' -0:increment an integer with incarg +0:incarg increments an integer >BUFFER: 1 >CURSOR: 1 zletest $'0\C-p' -0:decrement an integer with decarg +0:decarg decrements an integer >BUFFER: -1 >CURSOR: 2 zletest $'echo 0\e0\C-n' -0:increment an integer with vim-incarg +0:vim-incarg increments an integer >BUFFER: echo 1 >CURSOR: 5 zletest $'echo 0\e0\C-p' -0:decrement an integer with vim-decarg +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 @@ -57,42 +73,42 @@ zpty_run 'TMUX_PANE=0' zletest $'0\C-f' zpty_run 'unset TMUX_PANE' -0:sync-incarg on tmux in pane 0 +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 on tmux in pane 1 +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 on tmux in pane 2 +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 on tmux in pane 0 +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 on tmux in pane 1 +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 on tmux in pane 2 +0:sync-incarg increments by 2 on tmux in pane 2 >BUFFER: 2 >CURSOR: 1 @@ -100,230 +116,281 @@ zpty_run 'ITERM_SESSION_ID=w0t0p2:00000000-0000-0000-0000-000000000000' zletest $'0\C-f' zpty_run 'unset TMUX_PANE ITERM_SESSION_ID' -0:tmux pane number takes precedence over iTerm2's +0:sync-incarg prioritizes tmux pane number over iTerm2's >BUFFER: 1 >CURSOR: 1 zletest $'0\e2\C-n' -0:Providing a numeric argument will change the incremented amount +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:Setting the incarg variable will change the default incremented amount +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:A numeric argument will take precedence over the incarg variable +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:Providing a numeric argument will work for the sync- variants of incarg +0:The sync- variants of incarg takes the numeric argument into account >BUFFER: 4 >CURSOR: 0 +# Leading zeros + zletest $'000\C-n' -0:Incrementing a decimal integer preserves leading zeros +0:incarg preserves leading zeros of decimal integers >BUFFER: 001 >CURSOR: 3 zletest $'-001\C-n\C-n' -0:Leading zeros are preserved when the digit turns from negative to positive +0:incarg preserves leading zeros when the digit turns from negative to positive >BUFFER: 001 >CURSOR: 3 zletest $'001\C-p\C-p' -0:Leading zeros are preserved when the digit turns from positive to negative +0:incarg preserves leading zeros when the digit turns from positive to negative >BUFFER: -001 >CURSOR: 4 zletest $'001\e1000\C-n' -0:Incrementing an integer works when the result has more zeros than the original +0:incarg works when the result has more number of digits than the original >BUFFER: 1001 >CURSOR: 3 zletest $'001\e2000\C-p' -0:Decrementing an integer with leading zeros works when the result has more digits than the original +0:decargs works on integers with leading zeros when the result has more digits than the original >BUFFER: -1999 >CURSOR: 4 + zletest $'-000\C-n' +0:incarg produces the correct number of zeros when incrementing integers starting with -0 +>BUFFER: 001 +>CURSOR: 3 + + zletest $'-000\C-p' +0:decarg produces the correct number of zeros when incrementing integers starting with -0 +>BUFFER: -001 +>CURSOR: 4 + + zpty_run 'incarg=0' + zletest $'-000\C-n' + zpty_run 'unset incarg' +0:incarg removes the sign when the target integer starts with -0 and the increment amount is 0 +>BUFFER: 000 +>CURSOR: 3 + + zletest $'-0\C-n' +0:incarg turns -0 into 1 +>BUFFER: 1 +>CURSOR: 1 + + zletest $'-0\C-p' +0:decarg turns -0 into -1 +>BUFFER: -1 +>CURSOR: 2 + + zpty_run 'incarg=0' + zletest $'-0\C-n' + zpty_run 'unset incarg' +0:incarg turns -0 into 0 when the increment amount is 0 +>BUFFER: 0 +>CURSOR: 1 + +# Binaries + zletest $'0b11\C-n' -0:Increment a binary integer +0:incarg can increment a binary integer >BUFFER: 0b100 >CURSOR: 5 zletest $'0B11\C-n' -0:Increment a binary integer with an upper case prefix +0:incarg can increment a binary integer with an upper case prefix >BUFFER: 0B100 >CURSOR: 5 zletest $'0b100\C-p' -0:Decrement a binary integer +0:decarg can decrement a binary integer >BUFFER: 0b11 >CURSOR: 4 zletest $'0b0011\C-n' -0:Increment a binary integer preserves leading zeros +0:incarg can preserve leading zeros of binaries >BUFFER: 0b0100 >CURSOR: 6 zletest $'0b001\e8\C-n' -0:Incrementing a binary integer work when the result has more zeros than the original +0:incarg works on binaries when the result has more zeros than the original >BUFFER: 0b1001 >CURSOR: 5 zletest $'0b0\C-p' -0:Decrementing a binary integer to a negative value will fail +0:decarg fails to produce a negative binary value >BUFFER: 0b0 >CURSOR: 3 +# Octals + zletest $'0o7\C-n' -0:Increment an octal integer +0:incarg can increment an octal integer >BUFFER: 0o10 >CURSOR: 4 zletest $'0O7\C-n' -0:Increment an octal integer with an upper case prefix +0:incarg can increment an octal integer with an upper case prefix >BUFFER: 0O10 >CURSOR: 4 zletest $'0o10\C-p' -0:Decrement an octal integer +0:decarg can decrement an octal integer >BUFFER: 0o7 >CURSOR: 3 zletest $'0o0\C-p' -0:Decrementing an octal integer to a negative value will fail +0:decarg fails to produce a negative octal value >BUFFER: 0o0 >CURSOR: 3 +# Hexadecimals + zletest $'0x9\C-n' -0:Increment a hexadecimal integer +0:incarg can increment a hexadecimal integer >BUFFER: 0xa >CURSOR: 3 zletest $'0X9\C-n' -0:Increment a hexadecimal integer with an upper case prefix +0:incarg can increment a hexadecimal integer with an upper case prefix >BUFFER: 0XA >CURSOR: 3 zletest $'0xf\C-n' -0:Increment a hexadecimal integer with no numeric digit +0:incarg can increment a hexadecimal integer with no numeric digit >BUFFER: 0x10 >CURSOR: 4 zletest $'0x10\C-p' -0:Decrement a hexadecimal integer +0:decarg can decrement a hexadecimal integer >BUFFER: 0xf >CURSOR: 3 zletest $'0x0\C-p' -0:Decrementing an octal integer to a negative value will fail +0:decarg fails to produce a negative hexadecimal value >BUFFER: 0x0 >CURSOR: 3 zletest $'0x0b1\C-n' -0:a number that starts with 0x0b is interpreted as a hexadecimal integer +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:[0-9]0x[0-9a-f] will become [0-9]1x[0-9a-f] when incremented from the left of x +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:[0-9]0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on x +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:[0-9]0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on the right of x +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:[0-9]0b[01] will become [0-9]1b[01] when incremented from the left of b +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:[0-9]0b[01] will increment the binary 0b[01] when the cursor is on b +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:[0-9]0b[01] will increment the binary 0b[01] when the cursor is on the right of b +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:[0-9]0o[0-7] will become [0-9]1o[0-7] when incremented from the left of o +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:[0-9]0o[0-7] will increment the octal 0o[0-7] when the cursor is on o +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:[0-9]0o[0-7] will increment the octal 0o[0-7] when the cursor is on the right of o +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:0b0x[0-9a-f] will increment the binary 0b0 when the cursor is on the left of x +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:0b0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on top of x +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:0b0x[0-9a-f] will increment the hexadecimal 0x[0-9a-f] when the cursor is on the right of x +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 - 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 +# 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 @@ -355,6 +422,141 @@ >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 -- cgit v1.2.3 From 300ce96080b0679038db946ef34ac5c2d26646b5 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Fri, 24 May 2024 19:24:23 -0700 Subject: 52910: Improve handling of **/ patterns --- ChangeLog | 2 ++ Functions/Misc/zmv | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 642b40821..7f3412f8e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2024-05-24 Bart Schaefer + * 52910: Functions/Misc/zmv: Improve handling of **/ patterns + * 52904: Completion/Unix/Command/_git: Improve quoting of paths passed via _call_program to "git ls-files" diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv index 5c03e9ea1..2002af5a6 100644 --- a/Functions/Misc/zmv +++ b/Functions/Misc/zmv @@ -249,13 +249,13 @@ errs=() (( ${#files} )) || errs=( "no files matched \`$fpat'" ) for f in $files; do - if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then + if [[ $pat = (#b)(*)(\(\*\*##/\)|\*\*##/)(*) ]]; then # This looks like a recursive glob. This isn't good enough, - # because we should really enforce that $match[1] and $match[2] + # because we should really enforce that $match[1] and $match[3] # don't match slashes unless they were explicitly given. But # it's a start. It's fine for the classic case where (**/) is # at the start of the pattern. - pat="$match[1](*/|)$match[2]" + pat="$match[1](*/|)$match[3]" fi [[ -e $f && $f = (#b)${~pat} ]] || continue set -- "$match[@]" -- cgit v1.2.3 From d70b70ada6b84602dd7793e0416378d3b4d0a8ad Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 31 Mar 2025 15:17:42 -0700 Subject: 53413: "print -rP" in preview, in case of special characters --- ChangeLog | 5 +++++ Functions/Prompts/promptinit | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index a37a0f2ed..8668a7af5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2025-03-31 Bart Schaefer + + * Frank Dana: 53413: Functions/Prompts/promptinit: "print -rP" + in preview, in case of special characters + 2025-03-03 Oliver Kiddle * 53399: Src/Zle/zle_keymap.c, Src/builtin.c, Src/init.c, diff --git a/Functions/Prompts/promptinit b/Functions/Prompts/promptinit index 0c06699e8..7383c6c68 100644 --- a/Functions/Prompts/promptinit +++ b/Functions/Prompts/promptinit @@ -246,7 +246,7 @@ prompt_preview_theme () { # while the ZLE is not active. [[ -o promptcr ]] && print -n $'\r' - :; print -P -- "${PS1}command arg1 arg2 ... argn" + :; print -rP -- "${PS1}command arg1 arg2 ... argn" [[ -n ${preexec_functions[(r)prompt_${1}_preexec]} ]] && prompt_${1}_preexec -- cgit v1.2.3 From b707a60351bb9224fb808b3155dfef3288eef039 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Mon, 31 Mar 2025 15:22:00 -0700 Subject: 53414: attempting to preview the "restore" keyword is nonsensical --- ChangeLog | 4 ++++ Functions/Prompts/prompt_restore_setup | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 8668a7af5..ed79feb18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2025-03-31 Bart Schaefer + * Frank Dana: 53414: Functions/Prompts/prompt_restore_setup: + attempting to preview the "restore" keyword is nonsensical, + use a handler function to avoid messing up terminal output + * Frank Dana: 53413: Functions/Prompts/promptinit: "print -rP" in preview, in case of special characters diff --git a/Functions/Prompts/prompt_restore_setup b/Functions/Prompts/prompt_restore_setup index b77dbe815..c1f9bfb7e 100644 --- a/Functions/Prompts/prompt_restore_setup +++ b/Functions/Prompts/prompt_restore_setup @@ -1,3 +1,11 @@ -# Damn that was easy -zstyle -t :prompt-theme cleanup -zstyle -t :prompt-theme restore +prompt_restore_setup () { + # Damn that was easy + zstyle -t :prompt-theme cleanup + zstyle -t :prompt-theme restore +} + +prompt_restore_preview () { + echo "The prompt command 'restore' is not a theme and cannot be previewed." +} + +prompt_restore_setup "$@" -- cgit v1.2.3 From 84ef0c523878625feeed8cd0a5c142929d8b4d06 Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 27 Apr 2025 07:58:23 -0500 Subject: 53516: add zgetopt contrib function --- ChangeLog | 3 + Doc/Zsh/contrib.yo | 78 +++++++++++++++++++ Functions/Misc/zgetopt | 198 +++++++++++++++++++++++++++++++++++++++++++++++ NEWS | 5 +- Test/Z04zgetopt.ztst | 206 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 489 insertions(+), 1 deletion(-) create mode 100755 Functions/Misc/zgetopt create mode 100644 Test/Z04zgetopt.ztst (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 57050830f..de8fc6f3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2025-04-27 dana + * 53516: Doc/Zsh/contrib.yo, Functions/Misc/zgetopt, NEWS, + Test/Z04zgetopt.ztst: add zgetopt contrib function + * 53515: Test/B01cd.ztst: correct ztst documentation error 2025-04-20 Eric Cook diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index c1bea6022..030b63029 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -4672,6 +4672,84 @@ Same as tt(zmv -C) and tt(zmv -L), respectively. These functions do not appear in the zsh distribution, but can be created by linking tt(zmv) to the names tt(zcp) and tt(zln) in some directory in your tt(fpath). ) +findex(zgetopt) +item(tt(zgetopt) [ tt(-a) ] [ tt(-A) var(array) ] [ tt(-l) var(spec) ] [ tt(-n) var(name) ] [ tt(-o) var(spec) ] tt(--) [ var(args) ])( +This is a wrapper around tt(zparseopts) (from tt(zsh/zutil)) which +provides an interface similar to the util-linux implementation of +tt(getopt+LPAR()1+RPAR()) (sometimes called `GNU tt(getopt)'). It +simplifies GNU-style argument parsing (including permutation) and +can make it easier to write functions and scripts with complex APIs, +particularly ones where the order of options is significant. + +The typical usage pattern is as follows: + +example(zgetopt -o abc: -l aaa,bbb,ccc: -- "$@" || return +while (( $# )); do + case $1 in + -a|--aaa+RPAR() ...; shift ;; # handle -a + -b|--bbb+RPAR() ...; shift ;; # handle -b + -c|--ccc+RPAR() ...; shift 2 ;; # handle -c and arg + --+RPAR() ...; shift; break ;; # end of options + esac +done +# handle operands) + +It can also be called as a stand-alone script from other shells +using the more traditional print-and-eval pattern: + +example(args="$( zgetopt -n myscript -o abc: -l aaa,bbb,ccc: -- "$@" )" || return +eval set -- "$args" +while [ $# -ne 0 ]; do ...; done) + +Options: + +startsitem() +sitem(tt(-A var(array)))(When called as a function, assign the parsed +arguments to the named array var(array). Defaults to tt(argv), which +overwrites the caller's positional parameters. Has no meaning when +called as a script, in which case the parsed and quoted arguments are +always printed to standard output. An empty string forces the +printing behaviour in either mode.) +sitem(tt(-a))(Use Sun-style single-hyphenated long options instead of +GNU-style double-hyphenated ones (tt(-foo) vs tt(--foo)). Note that +long options with optional optargs can't always be distinguished +accurately from short options with optional optargs when using this +option. Also, due to limitations of tt(zparseopts), a Sun-style long +option whose name is only one character long is always treated as a +short option.) +sitem(tt(-l var(spec)))(Specify long options to recognise when +parsing. These should be given using just the option name (no +dashes), suffixed by `tt(:)' or `tt(::)' if it takes a mandatory or +optional argument respectively. Multiple options can be defined +either by separating them by commas or by supplying -l again. +Example: tt(-l foo,bar: -l baz)) +sitem(tt(-n var(name)))(Specify the name to use in the error message +if argument parsing fails. Defaults to the name of the nearest +calling function or the base name of tt($ZSH_ARGZERO). Note that +errors related to the usage of tt(zgetopt) itself are always reported +as coming from tt(zgetopt).) +sitem(tt(-o var(spec)))(Specify short options to recognise when +parsing. These should be given as a single string, in the same format +used by the tt(getopts) built-in or the tt(getopt+LPAR()3+RPAR()) +library function, again using `tt(:)' or `tt(::)' to indicate a +mandatory or optional argument. The spec may be prefixed with `tt(+)' +to indicate that option parsing should stop at the first non-option +argument (equivalent to setting the environment variable +tt(POSIXLY_CORRECT)). Example: tt(-o ab:cd::)) +endsitem() + +At least one of tt(-o) or tt(-l) must be given. The function's own +options should be followed by zero or more arguments to parse. It is +critical that these be separated explicitly by `tt(--)', as in the +above examples, to ensure that the function can accurately +distinguish the arguments it's meant to parse from its own. + +Refer to the manual for util-linux's tt(getopt+LPAR()1+RPAR()) for +more information about the way arguments are parsed and results are +returned. Note however that this function is not intended to be a +complete re-implementation. In particular, it omits all +portability/compatibility features. +) item(tt(zkbd))( See `Keyboard Definition' ifzman(above)\ diff --git a/Functions/Misc/zgetopt b/Functions/Misc/zgetopt new file mode 100755 index 000000000..5fc1e7725 --- /dev/null +++ b/Functions/Misc/zgetopt @@ -0,0 +1,198 @@ +#!/bin/zsh -f + +# Wrapper around zparseopts which gives it an interface similar to util-linux's +# getopt(1). See zshcontrib(1) for documentation + +emulate -L zsh -o extended_glob +zmodload -i zsh/zutil || return 3 + +# Very stupid and brittle internal wrapper around zparseopts used to insert the +# caller name into its error messages, allowing us to implement --name. This +# MUST be called with -v, since argv has the options to zparseopts itself +__zgetopt_zparseopts() { + local __err __ret + + __err=$( zparseopts "$@" 2>&1 ) + __ret=$? + + zparseopts "$@" &> /dev/null && return + + # Raw error message should look like this: + # zgetopt_zparseopts:zparseopts:3: bad option: -x + [[ -n $__err ]] && print -ru2 - ${__err/#*:zparseopts:<->:/$name:} + return __ret +} + +local optspec pat i posix=0 +local -a match mbegin mend optvv argvv +local -a array alt lopts sopts name +local -a specs no_arg_opts req_arg_opts opt_arg_opts tmp + +# Same as leading + in short-opts spec +(( $+POSIXLY_CORRECT )) && posix=1 + +# This 0=... makes any error message we get here look a little nicer when we're +# called as a script. Unfortunately the function name overrides $0 in +# zwarnnam() in other scenarios, so this can't be used to implement --name +0=${0:t} zparseopts -D -F -G - \ + {A,-array}:-=array \ + {a,-alternative}=alt \ + {l,-longoptions,-long-options}+:-=lopts \ + {n,-name}:-=name \ + {o,-options}:-=sopts \ +|| { + print -ru2 "usage: ${0:t} [-A ] [-a] [-l ] [-n ] [-o ] -- " + return 2 +} + +# Default to the caller's name +(( $#name )) && name=( "${(@)name/#(-n|--name=)/}" ) +[[ -n $name ]] || name=( ${funcstack[2]:-${ZSH_ARGZERO:t}} ) + +(( $#array )) && array=( "${(@)array/#(-A|--array=)/}" ) + +if [[ $ZSH_EVAL_CONTEXT != toplevel ]]; then + [[ $array == *[^A-Za-z0-9_.]* ]] && { + print -ru2 - "${0:t}: invalid array name: $array" + return 2 + } + (( $#array )) || array=( argv ) + +elif [[ -n $array ]]; then + print -ru2 - "${0:t}: -A option not meaningful unless called as function" + return 2 +fi + +# getopt requires a short option spec; we'll require either short or long +(( $#sopts || $#lopts )) || { + print -ru2 - "${0:t}: missing option spec" + return 2 +} + +optspec=${(@)sopts/#(-o|--options=)/} +sopts=( ) + +for (( i = 1; i <= $#optspec; i++ )); do + # Leading '+': Act POSIXLY_CORRECT + if [[ $i == 1 && $optspec[i] == + ]]; then + posix=1 + # Leading '-': Should leave operands interspersed with options, but this is + # not really possible with zparseopts + elif [[ $i == 1 && $optspec[i] == - ]]; then + print -ru2 - "${0:t}: optspec with leading - (disable operand collection) not supported" + return 2 + # Special characters: [+=\\] because they're special to zparseopts, ':' + # because it's special to getopt, '-' because it's the parsing terminator + elif [[ $optspec[i] == [+:=\\-] ]]; then + print -ru2 - "${0:t}: invalid short-option name: $optspec[i]" + return 2 + # 'a' + elif [[ $optspec[i+1] != : ]]; then + sopts+=( $optspec[i] ) + # 'a:' + elif [[ $optspec[i+2] != : ]]; then + sopts+=( $optspec[i]: ) + (( i += 1 )) + # 'a::' + elif [[ $optspec[i+3] != : ]]; then + sopts+=( $optspec[i]:: ) + (( i += 2 )) + fi +done + +lopts=( ${(@)lopts/#(-l|--long(|-)options=)/} ) +lopts=( ${(@s<,>)lopts} ) + +# Don't allow characters that are special to zparseopts in long-option specs. +# See above +pat='(*[+=\\]*|:*|*:::##|*:[^:]*)' +[[ -n ${(@M)lopts:#$~pat} ]] && { + print -ru2 - "${0:t}: invalid long-option spec: ${${(@M)lopts:#$~pat}[1]}" + return 2 +} + +(( $#alt )) || lopts=( ${(@)lopts/#/-} ) + +specs=( $sopts $lopts ) + +# Used below to identify options with optional optargs +no_arg_opts=( ${(@)${(@M)specs:#*[^:]}/#/-} ) +req_arg_opts=( ${(@)${(@)${(@M)specs:#*[^:]:}/#/-}/%:#} ) +opt_arg_opts=( ${(@)${(@)${(@M)specs:#*::}/#/-}/%:#} ) + +# getopt returns all instances of each option given, so add + +specs=( ${(@)specs/%(#b)(:#)/+$match[1]} ) + +# POSIXLY_CORRECT: Stop parsing options after first non-option argument +if (( posix )); then + tmp=( "$@" ) + __zgetopt_zparseopts -D -F -G -a optvv -v tmp - $specs || return 1 + argvv=( "${(@)tmp}" ) + +# Default: Permute options following non-option arguments +else + tmp=( "$@" ) + __zgetopt_zparseopts -D -E -F -G -a optvv -v tmp - $specs || return 1 + argv=( "${(@)tmp}" ) + # -D + -E leaves an explicit -- in argv where-ever it might appear + local seen + while (( $# )); do + [[ -z $seen && $1 == -- ]] && seen=1 && shift && continue + argvv+=( "$1" ) + shift + done +fi + +# getopt outputs all optargs as separate parameters, even missing optional ones, +# so we scan through and add/separate those if needed. This can't be perfectly +# accurate if Sun-style (-a) long options are used with optional optargs -- e.g. +# if you have specs a:: and abc::, then argument -abc=d is ambiguous. We don't +# guarantee which one is prioritised +(( $#opt_arg_opts )) && { + local cur next + local -a old_optvv=( "${(@)optvv}" ) + optvv=( ) + + for (( i = 1; i <= $#old_optvv; i++ )); do + cur=$old_optvv[i] + next=$old_optvv[i+1] + # Option with no optarg + if [[ -n ${no_arg_opts[(r)$cur]} ]]; then + optvv+=( $cur ) + # Option with required optarg -- will appear in next element + elif [[ -n ${req_arg_opts[(r)$cur]} ]]; then + optvv+=( $cur "$next" ) + (( i++ )) + # Long option with optional optarg -- will appear in same element delimited + # by '=' (even if missing) + elif [[ $cur == *=* && -n ${opt_arg_opts[(r)${cur%%=*}]} ]]; then + optvv+=( ${cur%%=*} "${cur#*=}" ) + # Short option with optional optarg -- will appear in same element with no + # delimiter (thus the option appears alone if the optarg is missing) + elif [[ -n ${opt_arg_opts[(r)${(M)cur#-?}]} ]]; then + optvv+=( ${(M)cur#-?} "${cur#-?}" ) + # ??? + else + print -ru2 - "${0:t}: parse error, please report!" + print -ru2 - "${0:t}: specs: ${(j< >)${(@q+)specs}}" + print -ru2 - "${0:t}: old_optvv: ${(j< >)${(@q+)old_optvv}}" + print -ru2 - "${0:t}: cur: $cur" + optvv+=( $cur ) # I guess? + fi + done +} + +if [[ -n $array ]]; then + # Use EXIT trap to assign in caller's context + trap "$array=( ${(j< >)${(@q+)optvv}} -- ${(j< >)${(@q+)argvv}} )" EXIT + +elif [[ $ZSH_EVAL_CONTEXT != toplevel ]]; then + print -r - "${(@q+)optvv}" -- "${(@q+)argvv}" + +# If called as a script, use unconditional single-quoting. This is ugly but it's +# the closest to what getopt does and it offers compatibility with legacy shells +else + print -r - "${(@qq)optvv}" -- "${(@qq)argvv}" +fi + +return 0 diff --git a/NEWS b/NEWS index 7c5e1e06b..a1e74b9fb 100644 --- a/NEWS +++ b/NEWS @@ -51,7 +51,7 @@ result via assignment to the named param rather than always via $REPLY. The shell now uses monotonic time instead of wall time for most internal time tracking, making it immune to system clock changes due to NTP, etc. For the most part this is transparent to users. However, as a -side effect, some features like $SECONDS and the time builtin gained +side effect, some features like $SECONDS and the time keyword gained (nominal) nanosecond precision. The zsh/zutil module's zparseopts builtin learnt a -v option which can @@ -60,6 +60,9 @@ be used to specify the array of arguments to parse instead of $@. The zparseopts builtin also learnt a -G option which enables GNU-style argument parsing ('--opt=arg', etc.). +A new contrib function zgetopt was added. It wraps `zparseopts -G` to +provide an interface similar to util-linux's getopt(1). + The module zsh/pcre has been updated to use the pcre2 library. The new zsh/random module defines an SRANDOM parameter, zrand_float() diff --git a/Test/Z04zgetopt.ztst b/Test/Z04zgetopt.ztst new file mode 100644 index 000000000..c2bc22be0 --- /dev/null +++ b/Test/Z04zgetopt.ztst @@ -0,0 +1,206 @@ +%prep + + autoload -Uz zgetopt + +%test + + zgetopt -A '' -- a b c + zgetopt -A '' -o '' -- a b c + zgetopt -A '' -l '' -- a b c +0:-o or -l required +?zgetopt: missing option spec +>-- a b c +>-- a b c + + zgetopt -A '' -o - -- a b c + zgetopt -A '' -o -a -- a b c + zgetopt -A '' -o a- -- a b c + zgetopt -A '' -o a+ -- a b c + zgetopt -A '' -o a= -- a b c + zgetopt -A '' -o a\\ -- a b c + zgetopt -A '' -o :a -- a b c + zgetopt -A '' -o a::: -- a b c + zgetopt -A '' -o '' -- a b c + zgetopt -A '' -o + -- a b c +0:weird short-option specs +?zgetopt: optspec with leading - (disable operand collection) not supported +?zgetopt: optspec with leading - (disable operand collection) not supported +?zgetopt: invalid short-option name: - +?zgetopt: invalid short-option name: + +?zgetopt: invalid short-option name: = +?zgetopt: invalid short-option name: \ +?zgetopt: invalid short-option name: : +?zgetopt: invalid short-option name: : +>-- a b c +>-- a b c + + zgetopt -A '' -l a,+ -- a b c + zgetopt -A '' -l a,= -- a b c + zgetopt -A '' -l a,\\ -- a b c + zgetopt -A '' -l a,: -- a b c + zgetopt -A '' -l a,:b -- a b c + zgetopt -A '' -l a,b:b -- a b c + zgetopt -A '' -l a,b::: -- a b c + zgetopt -A '' -l '' -- a b c + zgetopt -A '' -l , -- a b c + zgetopt -A '' -l a,,,,,b -- a b c + zgetopt -A '' -l - -- a b c --- +0:weird long-option specs +?zgetopt: invalid long-option spec: + +?zgetopt: invalid long-option spec: = +?zgetopt: invalid long-option spec: \ +?zgetopt: invalid long-option spec: : +?zgetopt: invalid long-option spec: :b +?zgetopt: invalid long-option spec: b:b +?zgetopt: invalid long-option spec: b::: +>-- a b c +>-- a b c +>-- a b c +>--- -- a b c + + zgetopt -A '' -o ab:c:: -- a b c + zgetopt -A '' -o ab:c:: -- -a + zgetopt -A '' -o ab:c:: -- -a a b c + zgetopt -A '' -o ab:c:: -- -a a -b c + zgetopt -A '' -o ab:c:: -- -a a -b -c + zgetopt -A '' -o ab:c:: -- -a a -b -c d + zgetopt -A '' -o ab:c:: -- -a a -b -c -c + zgetopt -A '' -o ab:c:: -- -a a -b -c -c d + zgetopt -A '' -o ab:c:: -- -a a -b -c -cd +0:short options +>-- a b c +>-a -- +>-a -- a b c +>-a -b c -- a +>-a -b -c -- a +>-a -b -c -- a d +>-a -b -c -c '' -- a +>-a -b -c -c '' -- a d +>-a -b -c -c d -- a + + zgetopt -A '' -l aaa,bbb:,ccc:: -- a b c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a b c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb=c + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc d + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc d + zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc=d +0:long options +>-- a b c +>--aaa -- +>--aaa -- a b c +>--aaa --bbb c -- a +>--aaa --bbb c -- a +>--aaa --bbb --ccc -- a +>--aaa --bbb --ccc -- a d +>--aaa --bbb --ccc --ccc '' -- a +>--aaa --bbb --ccc --ccc '' -- a d +>--aaa --bbb --ccc --ccc d -- a + + zgetopt -A '' -al aaa,bbb:,ccc:: -- a b c + zgetopt -A '' -al aaa,bbb:,ccc:: -- --aaa a b c + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a b c + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb c + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb=c + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc d + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc d + zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc=d +0:long options with -a (Sun style) +>-- a b c +?(eval): bad option: --aaa +>-aaa -- +>-aaa -- a b c +>-aaa -bbb c -- a +>-aaa -bbb c -- a +>-aaa -bbb -ccc -- a +>-aaa -bbb -ccc -- a d +>-aaa -bbb -ccc -ccc '' -- a +>-aaa -bbb -ccc -ccc '' -- a d +>-aaa -bbb -ccc -ccc d -- a + + zgetopt -A '' -al a: -- -a=b +0:single-character long option with -a +>-a '=b' -- + + zgetopt -A '' -o '' +0:zero args to parse +>-- + + zgetopt -A '' -o '' -- -- a b c + zgetopt -A '' -o '' -- a b -- c + zgetopt -A '' -o '' -- a b c -- + zgetopt -A '' -o c -- a b -- -c + zgetopt -A '' -o c -- a b - -c +0:parsing terminator +>-- a b c +>-- a b c +>-- a b c +>-- a b -c +>-c -- a b - + + zgetopt -A '' -o a -- a -a b + zgetopt -A '' -o +a -- a -a b + POSIXLY_CORRECT=1 zgetopt -A '' -o a -- a -a b +0:POSIXLY_CORRECT +>-a -- a b +>-- a -a b +>-- a -a b + + zgetopt -A '' -o '' -- $'\a\'\a' +0:function-mode quoting style +>-- $'\C-G\'\C-G' + + zgetopt -A '' -o '' -- a -a b + zgetopt -A '' -o '' -- a --a b +1:bad options +?(eval): bad option: -a +?(eval): bad option: --a + + zgetopt -A '' ; echo $? # missing spec + zgetopt -A '' -o '' -x ; echo $? # bad option to zgetopt + zgetopt -A '' -o '' -- -y; echo $? # bad option to parse +0:return status +*?zgetopt: missing option spec +*>2 +*?zgetopt:zparseopts:*: bad option: -x +*?usage:* +*>2 +*?\(eval\): bad option: -y +*>1 + + () { zgetopt -o a -- "$@"; typeset -p argv } -a b c + () { local -a v; zgetopt -A v -o a -- "$@"; typeset -p argv v } -a b c +0:array output +>typeset -g -a argv=( -a -- b c ) +>typeset -g -a argv=( -a b c ) +>typeset -a v=( -a -- b c ) + + zgetopt -A '' -o a: -- -x + zgetopt -A '' -o a: -- -a + () { zgetopt -A '' -o a: -- "$@"; : } -x + func() { zgetopt -A '' -o a: -- "$@"; : }; func -x + f1() { zgetopt -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x +0:automatic name +?(eval): bad option: -x +?(eval): missing argument for option: -a +?(anon): bad option: -x +?func: bad option: -x +?f1: bad option: -x + + zgetopt -n aaa -A '' -o a: -- -x + zgetopt -n aaa -A '' -o a: -- -a + () { zgetopt -n bbb -A '' -o a: -- "$@"; : } -x + func() { zgetopt -n ccc -A '' -o a: -- "$@"; : }; func -x + f1() { zgetopt -n ddd -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x +0:manual name with -n +?aaa: bad option: -x +?aaa: missing argument for option: -a +?bbb: bad option: -x +?ccc: bad option: -x +?ddd: bad option: -x -- cgit v1.2.3 From 80de57d5a63870e61a3d48efa1406ac05bbd2b5b Mon Sep 17 00:00:00 2001 From: dana Date: Mon, 28 Apr 2025 16:18:42 -0500 Subject: 53527: remove zgetopt reverts most of 84ef0c523, 0e369f37d, and 9b68cf38f feature was not ready. may be re-added after 5.10 release --- ChangeLog | 5 ++ Doc/Zsh/contrib.yo | 79 ------------------- Functions/Misc/zgetopt | 198 ----------------------------------------------- NEWS | 3 - Test/Z04zgetopt.ztst | 206 ------------------------------------------------- 5 files changed, 5 insertions(+), 486 deletions(-) delete mode 100755 Functions/Misc/zgetopt delete mode 100644 Test/Z04zgetopt.ztst (limited to 'Functions') diff --git a/ChangeLog b/ChangeLog index 441a5dd5a..cdcf5d5e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2025-04-28 dana + + * 53527: Doc/Zsh/contrib.yo, Functions/Misc/zgetopt, NEWS, + Test/Z04zgetopt.ztst: remove zgetopt (feature not ready) + 2025-04-27 dana * unposted: Doc/Zsh/contrib.yo, Doc/Zsh/mod_zutil.yo: diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 7822460e8..c1bea6022 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -4672,85 +4672,6 @@ Same as tt(zmv -C) and tt(zmv -L), respectively. These functions do not appear in the zsh distribution, but can be created by linking tt(zmv) to the names tt(zcp) and tt(zln) in some directory in your tt(fpath). ) -findex(zgetopt) -item(tt(zgetopt) [ tt(-a) ] [ tt(-A) var(array) ] [ tt(-l) var(spec) ] [ tt(-n) var(name) ] [ tt(-o) var(spec) ] tt(--) [ var(args) ])( -This is a wrapper around tt(zparseopts) (from tt(zsh/zutil)) which -provides an interface similar to the util-linux implementation of -tt(getopt+LPAR()1+RPAR()) (sometimes called `GNU tt(getopt)'). It -simplifies GNU-style argument parsing (including permutation) and -can make it easier to write functions and scripts with complex APIs, -particularly ones where the order of options is significant. - -The typical usage pattern is as follows: - -example(zgetopt -o abc: -l aaa,bbb,ccc: -- "$@" || return -while (( $# )); do - case $1 in - -a|--aaa+RPAR() ...; shift ;; # handle -a - -b|--bbb+RPAR() ...; shift ;; # handle -b - -c|--ccc+RPAR() ...; shift 2 ;; # handle -c and arg - --+RPAR() ...; shift; break ;; # end of options - esac -done -# handle operands) - -It can also be called as a stand-alone script from other shells -using the more traditional print-and-eval pattern: - -example(args="$( zgetopt -n myscript -o abc: -l aaa,bbb,ccc: -- "$@" )" || return -eval set -- "$args" -while [ $# -ne 0 ]; do ...; done) - -Options: - -startsitem() -sitem(tt(-A var(array)))(When called as a function, assign the parsed -arguments to the named array var(array). Defaults to tt(argv), which -overwrites the caller's positional parameters. Has no meaning when -called as a script, in which case the parsed and quoted arguments are -always printed to standard output. An empty string forces the -printing behaviour in either mode.) -sitem(tt(-a))(Use `alternative'-style single-hyphenated long options -instead of GNU-style double-hyphenated ones (tt(-foo) vs tt(--foo)). -Note that long options with optional optargs can't always be -distinguished accurately from short options with optional optargs -when using this option. Also, due to limitations of tt(zparseopts), -a single-hyphenated long option whose name is only one character long -is always treated as a short option.) -sitem(tt(-l var(spec)))(Specify long options to recognise when -parsing. These should be given using just the option name (no -dashes), suffixed by `tt(:)' or `tt(::)' if it takes a mandatory or -optional argument respectively. Multiple options can be defined -either by separating them by commas or by supplying -l again. -Example: tt(-l foo,bar: -l baz)) -sitem(tt(-n var(name)))(Specify the name to use in the error message -if argument parsing fails. Defaults to the name of the nearest -calling function or the base name of tt($ZSH_ARGZERO). Note that -errors related to the usage of tt(zgetopt) itself are always reported -as coming from tt(zgetopt).) -sitem(tt(-o var(spec)))(Specify short options to recognise when -parsing. These should be given as a single string, in the same format -used by the tt(getopts) built-in or the tt(getopt+LPAR()3+RPAR()) -library function, again using `tt(:)' or `tt(::)' to indicate a -mandatory or optional argument. The spec may be prefixed with `tt(+)' -to indicate that option parsing should stop at the first non-option -argument (equivalent to setting the environment variable -tt(POSIXLY_CORRECT)). Example: tt(-o ab:cd::)) -endsitem() - -At least one of tt(-o) or tt(-l) must be given. The function's own -options should be followed by zero or more arguments to parse. It is -critical that these be separated explicitly by `tt(--)', as in the -above examples, to ensure that the function can accurately -distinguish the arguments it's meant to parse from its own. - -Refer to the manual for util-linux's tt(getopt+LPAR()1+RPAR()) for -more information about the way arguments are parsed and results are -returned. Note however that this function is not intended to be a -complete re-implementation. In particular, it omits all -portability/compatibility features. Also, like tt(zparseopts) -itself, it does not support abbreviating long options. -) item(tt(zkbd))( See `Keyboard Definition' ifzman(above)\ diff --git a/Functions/Misc/zgetopt b/Functions/Misc/zgetopt deleted file mode 100755 index 5fc1e7725..000000000 --- a/Functions/Misc/zgetopt +++ /dev/null @@ -1,198 +0,0 @@ -#!/bin/zsh -f - -# Wrapper around zparseopts which gives it an interface similar to util-linux's -# getopt(1). See zshcontrib(1) for documentation - -emulate -L zsh -o extended_glob -zmodload -i zsh/zutil || return 3 - -# Very stupid and brittle internal wrapper around zparseopts used to insert the -# caller name into its error messages, allowing us to implement --name. This -# MUST be called with -v, since argv has the options to zparseopts itself -__zgetopt_zparseopts() { - local __err __ret - - __err=$( zparseopts "$@" 2>&1 ) - __ret=$? - - zparseopts "$@" &> /dev/null && return - - # Raw error message should look like this: - # zgetopt_zparseopts:zparseopts:3: bad option: -x - [[ -n $__err ]] && print -ru2 - ${__err/#*:zparseopts:<->:/$name:} - return __ret -} - -local optspec pat i posix=0 -local -a match mbegin mend optvv argvv -local -a array alt lopts sopts name -local -a specs no_arg_opts req_arg_opts opt_arg_opts tmp - -# Same as leading + in short-opts spec -(( $+POSIXLY_CORRECT )) && posix=1 - -# This 0=... makes any error message we get here look a little nicer when we're -# called as a script. Unfortunately the function name overrides $0 in -# zwarnnam() in other scenarios, so this can't be used to implement --name -0=${0:t} zparseopts -D -F -G - \ - {A,-array}:-=array \ - {a,-alternative}=alt \ - {l,-longoptions,-long-options}+:-=lopts \ - {n,-name}:-=name \ - {o,-options}:-=sopts \ -|| { - print -ru2 "usage: ${0:t} [-A ] [-a] [-l ] [-n ] [-o ] -- " - return 2 -} - -# Default to the caller's name -(( $#name )) && name=( "${(@)name/#(-n|--name=)/}" ) -[[ -n $name ]] || name=( ${funcstack[2]:-${ZSH_ARGZERO:t}} ) - -(( $#array )) && array=( "${(@)array/#(-A|--array=)/}" ) - -if [[ $ZSH_EVAL_CONTEXT != toplevel ]]; then - [[ $array == *[^A-Za-z0-9_.]* ]] && { - print -ru2 - "${0:t}: invalid array name: $array" - return 2 - } - (( $#array )) || array=( argv ) - -elif [[ -n $array ]]; then - print -ru2 - "${0:t}: -A option not meaningful unless called as function" - return 2 -fi - -# getopt requires a short option spec; we'll require either short or long -(( $#sopts || $#lopts )) || { - print -ru2 - "${0:t}: missing option spec" - return 2 -} - -optspec=${(@)sopts/#(-o|--options=)/} -sopts=( ) - -for (( i = 1; i <= $#optspec; i++ )); do - # Leading '+': Act POSIXLY_CORRECT - if [[ $i == 1 && $optspec[i] == + ]]; then - posix=1 - # Leading '-': Should leave operands interspersed with options, but this is - # not really possible with zparseopts - elif [[ $i == 1 && $optspec[i] == - ]]; then - print -ru2 - "${0:t}: optspec with leading - (disable operand collection) not supported" - return 2 - # Special characters: [+=\\] because they're special to zparseopts, ':' - # because it's special to getopt, '-' because it's the parsing terminator - elif [[ $optspec[i] == [+:=\\-] ]]; then - print -ru2 - "${0:t}: invalid short-option name: $optspec[i]" - return 2 - # 'a' - elif [[ $optspec[i+1] != : ]]; then - sopts+=( $optspec[i] ) - # 'a:' - elif [[ $optspec[i+2] != : ]]; then - sopts+=( $optspec[i]: ) - (( i += 1 )) - # 'a::' - elif [[ $optspec[i+3] != : ]]; then - sopts+=( $optspec[i]:: ) - (( i += 2 )) - fi -done - -lopts=( ${(@)lopts/#(-l|--long(|-)options=)/} ) -lopts=( ${(@s<,>)lopts} ) - -# Don't allow characters that are special to zparseopts in long-option specs. -# See above -pat='(*[+=\\]*|:*|*:::##|*:[^:]*)' -[[ -n ${(@M)lopts:#$~pat} ]] && { - print -ru2 - "${0:t}: invalid long-option spec: ${${(@M)lopts:#$~pat}[1]}" - return 2 -} - -(( $#alt )) || lopts=( ${(@)lopts/#/-} ) - -specs=( $sopts $lopts ) - -# Used below to identify options with optional optargs -no_arg_opts=( ${(@)${(@M)specs:#*[^:]}/#/-} ) -req_arg_opts=( ${(@)${(@)${(@M)specs:#*[^:]:}/#/-}/%:#} ) -opt_arg_opts=( ${(@)${(@)${(@M)specs:#*::}/#/-}/%:#} ) - -# getopt returns all instances of each option given, so add + -specs=( ${(@)specs/%(#b)(:#)/+$match[1]} ) - -# POSIXLY_CORRECT: Stop parsing options after first non-option argument -if (( posix )); then - tmp=( "$@" ) - __zgetopt_zparseopts -D -F -G -a optvv -v tmp - $specs || return 1 - argvv=( "${(@)tmp}" ) - -# Default: Permute options following non-option arguments -else - tmp=( "$@" ) - __zgetopt_zparseopts -D -E -F -G -a optvv -v tmp - $specs || return 1 - argv=( "${(@)tmp}" ) - # -D + -E leaves an explicit -- in argv where-ever it might appear - local seen - while (( $# )); do - [[ -z $seen && $1 == -- ]] && seen=1 && shift && continue - argvv+=( "$1" ) - shift - done -fi - -# getopt outputs all optargs as separate parameters, even missing optional ones, -# so we scan through and add/separate those if needed. This can't be perfectly -# accurate if Sun-style (-a) long options are used with optional optargs -- e.g. -# if you have specs a:: and abc::, then argument -abc=d is ambiguous. We don't -# guarantee which one is prioritised -(( $#opt_arg_opts )) && { - local cur next - local -a old_optvv=( "${(@)optvv}" ) - optvv=( ) - - for (( i = 1; i <= $#old_optvv; i++ )); do - cur=$old_optvv[i] - next=$old_optvv[i+1] - # Option with no optarg - if [[ -n ${no_arg_opts[(r)$cur]} ]]; then - optvv+=( $cur ) - # Option with required optarg -- will appear in next element - elif [[ -n ${req_arg_opts[(r)$cur]} ]]; then - optvv+=( $cur "$next" ) - (( i++ )) - # Long option with optional optarg -- will appear in same element delimited - # by '=' (even if missing) - elif [[ $cur == *=* && -n ${opt_arg_opts[(r)${cur%%=*}]} ]]; then - optvv+=( ${cur%%=*} "${cur#*=}" ) - # Short option with optional optarg -- will appear in same element with no - # delimiter (thus the option appears alone if the optarg is missing) - elif [[ -n ${opt_arg_opts[(r)${(M)cur#-?}]} ]]; then - optvv+=( ${(M)cur#-?} "${cur#-?}" ) - # ??? - else - print -ru2 - "${0:t}: parse error, please report!" - print -ru2 - "${0:t}: specs: ${(j< >)${(@q+)specs}}" - print -ru2 - "${0:t}: old_optvv: ${(j< >)${(@q+)old_optvv}}" - print -ru2 - "${0:t}: cur: $cur" - optvv+=( $cur ) # I guess? - fi - done -} - -if [[ -n $array ]]; then - # Use EXIT trap to assign in caller's context - trap "$array=( ${(j< >)${(@q+)optvv}} -- ${(j< >)${(@q+)argvv}} )" EXIT - -elif [[ $ZSH_EVAL_CONTEXT != toplevel ]]; then - print -r - "${(@q+)optvv}" -- "${(@q+)argvv}" - -# If called as a script, use unconditional single-quoting. This is ugly but it's -# the closest to what getopt does and it offers compatibility with legacy shells -else - print -r - "${(@qq)optvv}" -- "${(@qq)argvv}" -fi - -return 0 diff --git a/NEWS b/NEWS index a1e74b9fb..d5f6ab620 100644 --- a/NEWS +++ b/NEWS @@ -60,9 +60,6 @@ be used to specify the array of arguments to parse instead of $@. The zparseopts builtin also learnt a -G option which enables GNU-style argument parsing ('--opt=arg', etc.). -A new contrib function zgetopt was added. It wraps `zparseopts -G` to -provide an interface similar to util-linux's getopt(1). - The module zsh/pcre has been updated to use the pcre2 library. The new zsh/random module defines an SRANDOM parameter, zrand_float() diff --git a/Test/Z04zgetopt.ztst b/Test/Z04zgetopt.ztst deleted file mode 100644 index c2bc22be0..000000000 --- a/Test/Z04zgetopt.ztst +++ /dev/null @@ -1,206 +0,0 @@ -%prep - - autoload -Uz zgetopt - -%test - - zgetopt -A '' -- a b c - zgetopt -A '' -o '' -- a b c - zgetopt -A '' -l '' -- a b c -0:-o or -l required -?zgetopt: missing option spec ->-- a b c ->-- a b c - - zgetopt -A '' -o - -- a b c - zgetopt -A '' -o -a -- a b c - zgetopt -A '' -o a- -- a b c - zgetopt -A '' -o a+ -- a b c - zgetopt -A '' -o a= -- a b c - zgetopt -A '' -o a\\ -- a b c - zgetopt -A '' -o :a -- a b c - zgetopt -A '' -o a::: -- a b c - zgetopt -A '' -o '' -- a b c - zgetopt -A '' -o + -- a b c -0:weird short-option specs -?zgetopt: optspec with leading - (disable operand collection) not supported -?zgetopt: optspec with leading - (disable operand collection) not supported -?zgetopt: invalid short-option name: - -?zgetopt: invalid short-option name: + -?zgetopt: invalid short-option name: = -?zgetopt: invalid short-option name: \ -?zgetopt: invalid short-option name: : -?zgetopt: invalid short-option name: : ->-- a b c ->-- a b c - - zgetopt -A '' -l a,+ -- a b c - zgetopt -A '' -l a,= -- a b c - zgetopt -A '' -l a,\\ -- a b c - zgetopt -A '' -l a,: -- a b c - zgetopt -A '' -l a,:b -- a b c - zgetopt -A '' -l a,b:b -- a b c - zgetopt -A '' -l a,b::: -- a b c - zgetopt -A '' -l '' -- a b c - zgetopt -A '' -l , -- a b c - zgetopt -A '' -l a,,,,,b -- a b c - zgetopt -A '' -l - -- a b c --- -0:weird long-option specs -?zgetopt: invalid long-option spec: + -?zgetopt: invalid long-option spec: = -?zgetopt: invalid long-option spec: \ -?zgetopt: invalid long-option spec: : -?zgetopt: invalid long-option spec: :b -?zgetopt: invalid long-option spec: b:b -?zgetopt: invalid long-option spec: b::: ->-- a b c ->-- a b c ->-- a b c ->--- -- a b c - - zgetopt -A '' -o ab:c:: -- a b c - zgetopt -A '' -o ab:c:: -- -a - zgetopt -A '' -o ab:c:: -- -a a b c - zgetopt -A '' -o ab:c:: -- -a a -b c - zgetopt -A '' -o ab:c:: -- -a a -b -c - zgetopt -A '' -o ab:c:: -- -a a -b -c d - zgetopt -A '' -o ab:c:: -- -a a -b -c -c - zgetopt -A '' -o ab:c:: -- -a a -b -c -c d - zgetopt -A '' -o ab:c:: -- -a a -b -c -cd -0:short options ->-- a b c ->-a -- ->-a -- a b c ->-a -b c -- a ->-a -b -c -- a ->-a -b -c -- a d ->-a -b -c -c '' -- a ->-a -b -c -c '' -- a d ->-a -b -c -c d -- a - - zgetopt -A '' -l aaa,bbb:,ccc:: -- a b c - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a b c - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb c - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb=c - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc d - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc d - zgetopt -A '' -l aaa,bbb:,ccc:: -- --aaa a --bbb --ccc --ccc=d -0:long options ->-- a b c ->--aaa -- ->--aaa -- a b c ->--aaa --bbb c -- a ->--aaa --bbb c -- a ->--aaa --bbb --ccc -- a ->--aaa --bbb --ccc -- a d ->--aaa --bbb --ccc --ccc '' -- a ->--aaa --bbb --ccc --ccc '' -- a d ->--aaa --bbb --ccc --ccc d -- a - - zgetopt -A '' -al aaa,bbb:,ccc:: -- a b c - zgetopt -A '' -al aaa,bbb:,ccc:: -- --aaa a b c - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a b c - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb c - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb=c - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc d - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc d - zgetopt -A '' -al aaa,bbb:,ccc:: -- -aaa a -bbb -ccc -ccc=d -0:long options with -a (Sun style) ->-- a b c -?(eval): bad option: --aaa ->-aaa -- ->-aaa -- a b c ->-aaa -bbb c -- a ->-aaa -bbb c -- a ->-aaa -bbb -ccc -- a ->-aaa -bbb -ccc -- a d ->-aaa -bbb -ccc -ccc '' -- a ->-aaa -bbb -ccc -ccc '' -- a d ->-aaa -bbb -ccc -ccc d -- a - - zgetopt -A '' -al a: -- -a=b -0:single-character long option with -a ->-a '=b' -- - - zgetopt -A '' -o '' -0:zero args to parse ->-- - - zgetopt -A '' -o '' -- -- a b c - zgetopt -A '' -o '' -- a b -- c - zgetopt -A '' -o '' -- a b c -- - zgetopt -A '' -o c -- a b -- -c - zgetopt -A '' -o c -- a b - -c -0:parsing terminator ->-- a b c ->-- a b c ->-- a b c ->-- a b -c ->-c -- a b - - - zgetopt -A '' -o a -- a -a b - zgetopt -A '' -o +a -- a -a b - POSIXLY_CORRECT=1 zgetopt -A '' -o a -- a -a b -0:POSIXLY_CORRECT ->-a -- a b ->-- a -a b ->-- a -a b - - zgetopt -A '' -o '' -- $'\a\'\a' -0:function-mode quoting style ->-- $'\C-G\'\C-G' - - zgetopt -A '' -o '' -- a -a b - zgetopt -A '' -o '' -- a --a b -1:bad options -?(eval): bad option: -a -?(eval): bad option: --a - - zgetopt -A '' ; echo $? # missing spec - zgetopt -A '' -o '' -x ; echo $? # bad option to zgetopt - zgetopt -A '' -o '' -- -y; echo $? # bad option to parse -0:return status -*?zgetopt: missing option spec -*>2 -*?zgetopt:zparseopts:*: bad option: -x -*?usage:* -*>2 -*?\(eval\): bad option: -y -*>1 - - () { zgetopt -o a -- "$@"; typeset -p argv } -a b c - () { local -a v; zgetopt -A v -o a -- "$@"; typeset -p argv v } -a b c -0:array output ->typeset -g -a argv=( -a -- b c ) ->typeset -g -a argv=( -a b c ) ->typeset -a v=( -a -- b c ) - - zgetopt -A '' -o a: -- -x - zgetopt -A '' -o a: -- -a - () { zgetopt -A '' -o a: -- "$@"; : } -x - func() { zgetopt -A '' -o a: -- "$@"; : }; func -x - f1() { zgetopt -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x -0:automatic name -?(eval): bad option: -x -?(eval): missing argument for option: -a -?(anon): bad option: -x -?func: bad option: -x -?f1: bad option: -x - - zgetopt -n aaa -A '' -o a: -- -x - zgetopt -n aaa -A '' -o a: -- -a - () { zgetopt -n bbb -A '' -o a: -- "$@"; : } -x - func() { zgetopt -n ccc -A '' -o a: -- "$@"; : }; func -x - f1() { zgetopt -n ddd -A '' -o a: -- "$@"; : }; f2() { f1 "$@" }; f2 -x -0:manual name with -n -?aaa: bad option: -x -?aaa: missing argument for option: -a -?bbb: bad option: -x -?ccc: bad option: -x -?ddd: bad option: -x -- cgit v1.2.3