Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] Add execute-command() widget function (was Re: [RFC][PATCH] Add change-directory() widget function)



Thanks for the explanations. Here's a new patch.
From c6036cecbedc414e024049e1da3f66dadebd497f Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlon.richert@xxxxxxxxx>
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 [ <options> ] [--] <command> ...
+Execute commands from zle widget, without mangling prompt or buffer.
+Options:
+  -e         echo commands before executing
+  -s         save commands to history
+  -v <name>  store last command\'s exit status in param <name>'
+  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



Messages sorted by: Reverse Date, Date, Thread, Author