From c6036cecbedc414e024049e1da3f66dadebd497f Mon Sep 17 00:00:00 2001 From: Marlon Richert Date: Fri, 30 Apr 2021 21:59:07 +0300 Subject: [PATCH] Add `execute-commands` widget function --- Doc/Zsh/contrib.yo | 57 +++++++++++++++++++++++++++++++++++ Functions/Zle/execute-command | 41 +++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 Functions/Zle/execute-command diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 8bf1a208e..7d0acc10a 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2502,6 +2502,58 @@ arguments: example(zstyle :zle:edit-command-line editor gvim -f) ) +tindex(execute-commands) +tindex(cd-upward) +tindex(cd-backward) +tindex(cd-forward) +item(tt(execute-commands) [ var(options) ] [--] var(command) ...)( +This function helps you implement widgets that execute commands (passed to the +function as string arguments) without losing the current command line, in a +fashion similar to the tt(run-help) and tt(which-command) widgets (see +ifzman(the subsection bf(Miscellaneous) in zmanref(zshzle))\ +ifnzman(noderef(ZLE widgets standard Miscellaneous))). You can use this, for +example, to create key bindings that let you instantly change directories, even +while in the middle of typing another command: + +example(autoload -Uz execute-commands +zle -N cd-parent; cd-parent+LPAR()+RPAR() { + execute-commands -- 'cd ..' +} +zle -N pushd-prev; pushd-prev+LPAR()+RPAR() { + local sign='+'; [[ -o pushdminus ]] && sign='-' + execute-commands -- "pushd ${sign}1 > /dev/null" +} +zle -N pushd-next; pushd-next+LPAR()+RPAR() { + local sign='-'; [[ -o pushdminus ]] && sign='+' + execute-commands -- "pushd ${sign}0 > /dev/null" +} +bindkey "^[$terminfo[cuu1]" cd-parent # Alt-Up in raw mode +bindkey "^[$terminfo[kcuu1]" cd-parent # Alt-Up in app mode +bindkey '^[-' pushd-prev # Alt-Minus +bindkey '^[=' pushd-next # Alt-Equals) + +By default, tt(execute-commands) executes the supplied commands quietly and +without saving them to history. Its behavior can be modified by setting the +following options: +startsitem() +sitem(tt(-e))( +Echo the commands to the command line before executing them. +) +sitem(tt(-s))( +Save the commands to history. +) +sitem(tt(-v) var(name))( +Store the last command's exit code in parameter var(name). +) +endsitem() + +Note that calling tt(execute-commands) should always be the only or last +statement you execute in your widget, because (after executing the supplied +commands) tt(execute-commands) causes execution of the current widget to be +aborted. Also note that tt(execute-commands) cannot be used when inside a +tt(select) loop or tt(vared). Under those circumstances, it does nothing and +returns non-zero. +) tindex(expand-absolute-path) item(tt(expand-absolute-path))( Expand the file name under the cursor to an absolute path, resolving @@ -4649,6 +4701,11 @@ See `Recompiling Functions' ifzman(above)\ ifnzman((noderef(Utilities))). ) +findex(zrestart) +item(tt(zrestart))( +This function tests whether the shell is able to restart without error and, if +so, restarts the shell. +) findex(zstyle+) item(tt(zstyle+) var(context) var(style) var(value) [ tt(+) var(subcontext) var(style) var(value) ... ])( This makes defining styles a bit simpler by using a single `tt(+)' as a diff --git a/Functions/Zle/execute-command b/Functions/Zle/execute-command new file mode 100644 index 000000000..f8e25f54e --- /dev/null +++ b/Functions/Zle/execute-command @@ -0,0 +1,41 @@ +# Lets you implement widgets that can execute arbitrary commands without losing +# the current command line, in a fashion similar to the 'run-help' and +# 'which-command' widgets. See the manual for more details. + +zmodload -F zsh/zutil b:zparseopts +local -A opts +zparseopts -D -A opts - e s v: + +local -a err +zle || + err+=( "${0}: can only be called from zle widgets" ) +(( # )) || + err+=( "${0}: not enough arguments" ) +if [[ -n $err ]]; then + print -lu2 -- $err[@] \ +$'Usage: execute-commands [ ] [--] ... +Execute commands from zle widget, without mangling prompt or buffer. +Options: + -e echo commands before executing + -s save commands to history + -v store last command\'s exit status in param ' + return 1 +fi + +case $CONTEXT in + ( cont | start ) + print -rz -- "$PREBUFFER$BUFFER" # Push all lines to buffer stack. + [[ -v opts[-e] ]] && + BUFFER="${(F)@}" # Echo commands to buffer. + [[ -v opts[-s] ]] && + print -rS -- "${(F)@}" # Save commands to history. + eval "${(F)@}" # Execute commands. + local -i ret=$? + [[ -v opts[-v] ]] && + eval "$opts[-v]=$ret" # Store exit status. + ;; + ( * ) + return 75 # EX_TEMPFAIL; see `man 3 sysexits`. + ;; +esac +zle .send-break -- 2.31.1