zsh-workers
 help / color / mirror / code / Atom feed
From: Marlon Richert <marlon.richert@gmail.com>
To: Bart Schaefer <schaefer@brasslantern.com>
Cc: Daniel Shahaf <d.s@daniel.shahaf.name>,
	Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [PATCH] Add execute-command() widget function (was Re: [RFC][PATCH] Add change-directory() widget function)
Date: Thu, 22 Apr 2021 13:55:35 +0300	[thread overview]
Message-ID: <214AC3E9-FFA5-4F39-A918-562682FE3A3B@gmail.com> (raw)
In-Reply-To: <CAH+w=7bFfZucFRj9OZvzTnvxd+QUW7tZHAJiMLi+O0PNjz=wyA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5631 bytes --]

New version of the patch attached. Follow-ups to unresolved discussion points below.


On 22 Apr 2021, at 00:58, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Wed, Apr 21, 2021 at 2:28 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>> Again, please wrap long lines in your prose.  This is the third time you
>> are being asked to do so.

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.


>> As to PUSHD_MINUS and PUSHD_SILENT, it would be better to give an
>> example doesn't change them from their default values.

Why exactly?


> Using "pushd -q ..." avoids the need for PUSHD_SILENT.  

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.


>>> +    # 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.
>>> +    zle .push-line-or-edit
>>> +    return  # Not actually necessary, but for clarity's sake
>> 
>> How is it not necessary?  If control flow continued past the «esac»,
>> code would be executed.
> 
> Flow can't continue past «zle .push-line-or-edit» because it invokes
> the equivalent of send-break and kills the widget.  But I still don't
> understand why he wants this here.

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@daniel.shahaf.name> wrote:
>> +ifnzman(noderef(Miscellaneous))). More precisely, it 
> 
> s/it/it:|it+DASH()-/ ?

Sorry, I’m new to Yodl. What exactly would that do and why would we need that here?


>> +enumeration(
>> +myeit() pushes the buffer onto the buffer stack, 
>> +myeit() executes the supplied arguments, then 
>> +myeit() lets the ZLE pop the buffer off the top of the buffer stack and load 
>> +  it into the editing buffer.
> 
> Should the precise implementation be documented here?  If the
> implementation strategy is seen as an API promise, it would be more
> difficult to change it later.
> 
> Describing what the function actually _does_ (as distinguished from what
> sort of context it's typically used in) is of course relevant;
> cf. [workers/45152, fifth hunk].

It’s about the same level of detail as given for run-help, which-command and push-line-or-edit.


>> +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
> 
> AUTO_PUSHD is set but not used.

If I wouldn’t set it, then the names cd-backward and cd-forward  wouldn’t make any sense anymore.


> As to PUSHD_MINUS and PUSHD_SILENT, it would be better to give an
> example doesn't change them from their default values.  That's again
> 45149, which I mentioned just yesterday.

Let’s suppose the following:
I rewrite the example to use `pushd +1` and `pushd -0`, so it works with default shell options.
A novice user has PUSHD_MINUS in their config (for whatever reason; they might not even know what it does).
They copy-paste the example.
Now the widgets won’t work at all as expected. It’s not even the reverse.

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.


>> +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 }
> 
> s/()/+LPAR()+RPAR()/ so they don't look like yodl macros (and
> potentially throw build-time warnings).  (For Vim users, the custom
> ftplugin sets up concealing which does the reverse replacement while
> editing.)

Again, sorry, I’m new to Yodl. What exactly are you suggesting?


>> +bindkey '^[^[[A' cd-upward; bindkey '^[^[OA' cd-upward
> 
> -1 on using random escape sequences without any explanation of what they
> do and how to find them out.
> 
> Can the symbolic names of these escape sequences be used here?  At least
> .
>    % for k v in "${(@kv)terminfo}" ; [[ $v == (*\[A*|*OA*) ]] && echo $k 
>    cuu1
>    kcuu1
> .
> if we don't have anything more human-readable than those.  (I think this
> was discussed somewhere in the "default zshrc" thread so I won't
> elaborate here.)

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.





[-- Attachment #2.1: Type: text/html, Size: 9891 bytes --]

[-- Attachment #2.2: 0001-Add-execute-command-widget-function.txt --]
[-- Type: text/plain, Size: 4667 bytes --]

From caed732b7c9015b2fb692d3c894236b76202a979 Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlon.richert@gmail.com>
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


[-- Attachment #2.3: Type: text/html, Size: 252 bytes --]

  reply	other threads:[~2021-04-22 10:56 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-20 13:36 [RFC][PATCH] Add change-directory() widget function Marlon Richert
2021-04-20 19:43 ` Bart Schaefer
2021-04-20 20:13   ` Marlon Richert
2021-04-20 21:32     ` Bart Schaefer
2021-04-21  3:46       ` Bart Schaefer
2021-04-21 11:37         ` [PATCH] Add execute-command() widget function (was Re: [RFC][PATCH] Add change-directory() widget function) Marlon Richert
2021-04-21 20:40           ` Bart Schaefer
2021-04-21 21:27           ` Daniel Shahaf
2021-04-21 21:58             ` Bart Schaefer
2021-04-22 10:55               ` Marlon Richert [this message]
2021-04-22 20:25                 ` Daniel Shahaf
2021-04-22 23:27                 ` Bart Schaefer
2021-04-24 20:06                   ` Marlon Richert
2021-04-24 21:49                     ` Bart Schaefer
2021-04-24 21:58                       ` Bart Schaefer
2021-04-26 18:08                         ` Marlon Richert
2021-04-26 21:39                           ` Bart Schaefer
2021-04-27 10:46                             ` Marlon Richert
2021-04-27 19:27                               ` Bart Schaefer
2021-04-30 19:16                                 ` Marlon Richert
2021-04-30 20:25                                   ` Bart Schaefer
2021-05-01 13:30                                     ` Marlon Richert
2021-05-31 17:55                                       ` Marlon Richert
2021-04-25 17:02                     ` Hard-wrapping emails (Was: [PATCH] Add execute-command() widget function (was Re: [RFC][PATCH] Add change-directory() widget function)) Lawrence Velázquez
2021-04-20 21:57     ` [RFC][PATCH] Add change-directory() widget function Daniel Shahaf
2021-04-20 22:14     ` Daniel Shahaf
2021-04-21  0:09       ` Bart Schaefer
2021-04-21  3:18       ` Bart Schaefer
2021-04-21 20:11         ` Daniel Shahaf
2021-04-21 20:29           ` Bart Schaefer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=214AC3E9-FFA5-4F39-A918-562682FE3A3B@gmail.com \
    --to=marlon.richert@gmail.com \
    --cc=d.s@daniel.shahaf.name \
    --cc=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).