New version of the patch attached. Follow-ups to unresolved discussion points below.
I would love to, but I’m not sure when it happens (everything looks fine on my end) and I haven’t found an explicit setting for it in my email client. Please let me know if this email has long lines or not. That would help me figure out which combination of settings might be causing this.
Why exactly?
Except `pushd -q` has the side effect of "the hook function chpwd and the functions in the array $chpwd_functions are not called" (according to the manual). That’s not something that I would want when changing dirs interactively.
If I would use push-input instead of push-line-or-edit, the buffer would not get restored immediately after using the widget. You’d end up with a blank command line instead. I want it to work the same from PS2 as it does from PS1. On 22 Apr 2021, at 00:27, Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx> wrote:
Sorry, I’m new to Yodl. What exactly would that do and why would we need that here?
It’s about the same level of detail as given for run-help, which-command and push-line-or-edit.
If I wouldn’t set it, then the names cd-backward and cd-forward wouldn’t make any sense anymore.
Let’s suppose the following:
Setting PUSHD_MINUS in the example guarantees that it will work out of the box for novice users. (More advanced users, I’m sure, will be able to figure out how to modify it to suit their needs.) As for PUSHD_SILENT, as I pointed out above, using `pushd -q` instead has unwanted side effects. It does not have an interchangeable alternative.
Again, sorry, I’m new to Yodl. What exactly are you suggesting?
For cuu1 and cuf1, that would work, but ^[[B and ^[[D do not have entries in terminfo. I don’t think we should use $terminfo[cuu1] and $terminfo[cuf1] in some examples but then hard-code ^[[B and ^[[D elsewhere. Hard-coding all of ^[[{A..D} would be more clear. I’m fine using $terminfo for kcuu1, kcud1, kcuf1 and kcub1. Using $key[Up] would be even better, but we cannot rely on that being set. |
From caed732b7c9015b2fb692d3c894236b76202a979 Mon Sep 17 00:00:00 2001 From: Marlon Richert <marlon.richert@xxxxxxxxx> Date: Thu, 22 Apr 2021 13:36:56 +0300 Subject: [PATCH] Add execute-command() widget function --- Doc/Zsh/contrib.yo | 34 ++++++++++++++++++++++ Functions/Zle/execute-command | 54 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 Functions/Zle/execute-command diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 8bf1a208e..64388ed70 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2502,6 +2502,40 @@ arguments: example(zstyle :zle:edit-command-line editor gvim -f) ) +tindex(execute-command) +tindex(cd-upward) +tindex(cd-backward) +tindex(cd-forward) +item(tt(execute-command))( +This function lets you implement a widget that executes a specified command +(passed as a single string argument) 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))). More precisely, it +enumeration( +eit() pushes the buffer onto the buffer stack, then +eit() executes the supplied argument string, then +eit() lets the ZLE pop the buffer off the top of the buffer stack and load + it into the editing buffer. +) + +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-command +setopt autopushd pushdminus pushdsilent +zle -N cd-upward ; cd-upward() { execute-command -- 'cd ..' } +zle -N cd-backward; cd-backward() { execute-command -- 'pushd -1' } +zle -N cd-forward ; cd-forward() { execute-command -- 'pushd +0' } +bindkey '^[[A' cd-upward # Alt-Up in raw mode +bindkey "$terminfo[kcuu1]" cd-upward # Alt-Up in app mode +bindkey '^[-' cd-backward # Alt-Minus +bindkey '^[=' cd-forward # Alt-Equals) + +Note that widgets created with this function cannot be used inside a tt(select) +loop or tt(vared). Under those circumstances, the function 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 diff --git a/Functions/Zle/execute-command b/Functions/Zle/execute-command new file mode 100644 index 000000000..4014fa854 --- /dev/null +++ b/Functions/Zle/execute-command @@ -0,0 +1,54 @@ +# Lets you implement widgets that can execute arbitrary commands without losing +# the current command line, in a fashion similar to 'run-help' and +# 'which-command' widgets. See the manual for examples. + +zmodload -F zsh/zutil b:zparseopts +autoload -Uz add-zle-hook-widget + +case $CONTEXT in + ( start ) # PS1 + ;; + ( cont ) # PS2 + # Add a one-time hook that will re-run this widget at the top-level prompt. + local hook=line-init + local func=${(q):-:${(%):-%N}:$hook:$WIDGET} + eval "$func() { + # Make sure we don't run twice. + add-zle-hook-widget -d $hook $func + + # Don't leave anything behind. + zle -D $func + unfunction $func + + # Use -w to ensure \$WIDGET is set to our original widget, not the hook. + # This doesn't matter at present, but might matter in future or if this + # code gets copy-pasted elsewhere. + zle ${(q)WIDGET} -w + }" + add-zle-hook-widget $hook ${(Q)func} + + # Move the entire current multiline construct into the editor buffer. This + # function is then aborted and we return to the top-level prompt, which + # triggers the hook above. + # We don't use .push-input here, because that would result in a blank + # buffer afterwards. + zle .push-line-or-edit + return # Command flow never actually gets here. See above. + ;; + ( * ) + # We don't want this to be used in a select loop or in vared: + # * At a select prompt, the command wouldn't be "executed"; it'd be fed to + # select as the value of the selection. + # * In vared, it would replace the contents of the variable with the + # command string and then exit vared. + return 75 # EX_TEMPFAIL; see `man 3 sysexits`. + ;; +esac + +# Push the current buffer onto the buffer stack and clear the buffer. The ZLE +# will auto-restore it at the next top-level prompt. +zle .push-line + +zparseopts -D - # Remove - or -- argument. +BUFFER="$1" +zle .accept-line -- 2.31.1