zsh-users
 help / color / mirror / Atom feed
* How to avoid infinite recursion in ZLE widgets
@ 2020-09-23  8:34 Peter Slížik
  2020-09-23 11:21 ` Peter Stephenson
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Peter Slížik @ 2020-09-23  8:34 UTC (permalink / raw)
  To: zsh-users

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

Hello,

I'd like to replicate the functionality found in some text editors - namely
that if you press a single or double quote, the editor inserts two of them
and places the cursor inside the pair.

With some necessary checks for word boundaries, etc. left out, the solution
looks rather trivial:

function insert-single-quotes() {
    zle self-insert "''"    # that's "_'_'_"
    zle backward-char
}

zle -N insert-single-quotes
bindkey "'" insert-single-quotes    # that's "_'_"

However, this solution creates infinite recursion (a single quote bound to
insert a single quote).

1. How to prevent the recursion? Is self-insert the right widget for this
task?
2. I played with zle -U. What are the use cases for zle self-insert and zle
-U?
3. I tried to avoid the recursion by using "zle -K .safe -U text", but it
ended with "too many arguments for -K". How is zle -K expected to be used?

Thanks for your time,
Peter Slížik

[-- Attachment #2: Type: text/html, Size: 1320 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23  8:34 How to avoid infinite recursion in ZLE widgets Peter Slížik
@ 2020-09-23 11:21 ` Peter Stephenson
  2020-09-23 11:24   ` Peter Slížik
  2020-09-23 11:29 ` Daniel Shahaf
  2020-09-23 18:25 ` zsugabubus
  2 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2020-09-23 11:21 UTC (permalink / raw)
  To: zsh-users

> On 23 September 2020 at 09:34 Peter Slížik <peter.slizik@gmail.com> wrote:
> I'd like to replicate the functionality found in some text editors - namely
> that if you press a single or double quote, the editor inserts two of them
> and places the cursor inside the pair.
> 
> With some necessary checks for word boundaries, etc. left out, the solution
> looks rather trivial:
> 
> function insert-single-quotes() {
>     zle self-insert "''"    # that's "_'_'_"
>     zle backward-char
> }

The right way to insert something into the buffer at this point is using
the special variables.  You can add a quote before and a quote after
the cursor using:

insert-single-quotes() {
    LBUFFER+="'"
    RBUFFER="'$RBUFFER"
}

pws


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23 11:21 ` Peter Stephenson
@ 2020-09-23 11:24   ` Peter Slížik
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Slížik @ 2020-09-23 11:24 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-users

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

That's great!

Thank you for the idea.

Peter

сре, 23. сеп 2020. у 13:21 Peter Stephenson <p.w.stephenson@ntlworld.com>
је написао/ла:

> > On 23 September 2020 at 09:34 Peter Slížik <peter.slizik@gmail.com>
> wrote:
> > I'd like to replicate the functionality found in some text editors -
> namely
> > that if you press a single or double quote, the editor inserts two of
> them
> > and places the cursor inside the pair.
> >
> > With some necessary checks for word boundaries, etc. left out, the
> solution
> > looks rather trivial:
> >
> > function insert-single-quotes() {
> >     zle self-insert "''"    # that's "_'_'_"
> >     zle backward-char
> > }
>
> The right way to insert something into the buffer at this point is using
> the special variables.  You can add a quote before and a quote after
> the cursor using:
>
> insert-single-quotes() {
>     LBUFFER+="'"
>     RBUFFER="'$RBUFFER"
> }
>
> pws
>
>

[-- Attachment #2: Type: text/html, Size: 1539 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23  8:34 How to avoid infinite recursion in ZLE widgets Peter Slížik
  2020-09-23 11:21 ` Peter Stephenson
@ 2020-09-23 11:29 ` Daniel Shahaf
  2020-09-23 11:32   ` Peter Slížik
  2020-09-23 18:25 ` zsugabubus
  2 siblings, 1 reply; 13+ messages in thread
From: Daniel Shahaf @ 2020-09-23 11:29 UTC (permalink / raw)
  To: Peter Slížik; +Cc: zsh-users

Peter Slížik wrote on Wed, 23 Sep 2020 10:34 +0200:
> Hello,
> 
> I'd like to replicate the functionality found in some text editors - namely
> that if you press a single or double quote, the editor inserts two of them
> and places the cursor inside the pair.
> 
> With some necessary checks for word boundaries, etc. left out, the solution
> looks rather trivial:
> 
> function insert-single-quotes() {
>     zle self-insert "''"    # that's "_'_'_"
>     zle backward-char
> }  
> 
> zle -N insert-single-quotes
> bindkey "'" insert-single-quotes    # that's "_'_"
> 
> However, this solution creates infinite recursion (a single quote bound to
> insert a single quote).

No, it doesn't.  I tried in «zsh -f» and it inserts a single quote
without moving the cursor.

It inserts _one_ quote, rather than two, because self-insert ignores
its positional arguments and the widget was bound to «'».

> 1. How to prevent the recursion?

Always open a new shell for testing.

> Is self-insert the right widget for this task?

You could also use «zle .self-insert», or even modify $LBUFFER and
$RBUFFER directly («LBUFFER+=\'; RBUFFER=\'$RBUFFER»).

(Incidentally, I guess you may also want to check whether ${RBUFFER}
starts with a single quote, but that's no longer a zsh question but
a business logic question.)

> 2. I played with zle -U. What are the use cases for zle self-insert and zle
> -U?

«zle -U foo» subjects the «f», «o», and «o» to bindkey mappings.  For
instance, «bindkey -s x y» followed by «zle -U x» would insert «y».

«self-insert» appends one character to the buffer.

> 3. I tried to avoid the recursion by using "zle -K .safe -U text", but it
> ended with "too many arguments for -K". How is zle -K expected to be used?

As «zle -K foo» without further arguments.  You can do something like this:

    {
        readonly save_KEYMAP=$KEYMAP
        zle -K .safe
        ⋮
    } always {
        zle -K $save_KEYMAP
    }

But see above about $LBUFFER.

Cheers,

Daniel


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23 11:29 ` Daniel Shahaf
@ 2020-09-23 11:32   ` Peter Slížik
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Slížik @ 2020-09-23 11:32 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: zsh-users

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

Thanks, Daniel!

Peter

сре, 23. сеп 2020. у 13:29 Daniel Shahaf <d.s@daniel.shahaf.name> је
написао/ла:

> Peter Slížik wrote on Wed, 23 Sep 2020 10:34 +0200:
> > Hello,
> >
> > I'd like to replicate the functionality found in some text editors -
> namely
> > that if you press a single or double quote, the editor inserts two of
> them
> > and places the cursor inside the pair.
> >
> > With some necessary checks for word boundaries, etc. left out, the
> solution
> > looks rather trivial:
> >
> > function insert-single-quotes() {
> >     zle self-insert "''"    # that's "_'_'_"
> >     zle backward-char
> > }
> >
> > zle -N insert-single-quotes
> > bindkey "'" insert-single-quotes    # that's "_'_"
> >
> > However, this solution creates infinite recursion (a single quote bound
> to
> > insert a single quote).
>
> No, it doesn't.  I tried in «zsh -f» and it inserts a single quote
> without moving the cursor.
>
> It inserts _one_ quote, rather than two, because self-insert ignores
> its positional arguments and the widget was bound to «'».
>
> > 1. How to prevent the recursion?
>
> Always open a new shell for testing.
>
> > Is self-insert the right widget for this task?
>
> You could also use «zle .self-insert», or even modify $LBUFFER and
> $RBUFFER directly («LBUFFER+=\'; RBUFFER=\'$RBUFFER»).
>
> (Incidentally, I guess you may also want to check whether ${RBUFFER}
> starts with a single quote, but that's no longer a zsh question but
> a business logic question.)
>
> > 2. I played with zle -U. What are the use cases for zle self-insert and
> zle
> > -U?
>
> «zle -U foo» subjects the «f», «o», and «o» to bindkey mappings.  For
> instance, «bindkey -s x y» followed by «zle -U x» would insert «y».
>
> «self-insert» appends one character to the buffer.
>
> > 3. I tried to avoid the recursion by using "zle -K .safe -U text", but it
> > ended with "too many arguments for -K". How is zle -K expected to be
> used?
>
> As «zle -K foo» without further arguments.  You can do something like this:
>
>     {
>         readonly save_KEYMAP=$KEYMAP
>         zle -K .safe
>         ⋮
>     } always {
>         zle -K $save_KEYMAP
>     }
>
> But see above about $LBUFFER.
>
> Cheers,
>
> Daniel
>

[-- Attachment #2: Type: text/html, Size: 3020 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23  8:34 How to avoid infinite recursion in ZLE widgets Peter Slížik
  2020-09-23 11:21 ` Peter Stephenson
  2020-09-23 11:29 ` Daniel Shahaf
@ 2020-09-23 18:25 ` zsugabubus
  2020-09-24  9:55   ` Peter Slížik
  2 siblings, 1 reply; 13+ messages in thread
From: zsugabubus @ 2020-09-23 18:25 UTC (permalink / raw)
  To: Peter Slížik; +Cc: zsh-users

Hello,

On Wed, Sep 23, 2020 at 10:34:50AM +0200, Peter Slížik wrote:
> I'd like to replicate the functionality found in some text editors - namely
> that if you press a single or double quote, the editor inserts two of them
> and places the cursor inside the pair.

What about simply modifying the buffer like this:

function insert-single-quotes() {
  LBUFFER+="'"
  RBUFFER="'$RBUFFER"
}

> zle -N insert-single-quotes
> bindkey "'" insert-single-quotes    # that's "_'_"

-- 
zsugabubus


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-23 18:25 ` zsugabubus
@ 2020-09-24  9:55   ` Peter Slížik
  2020-09-25 14:19     ` Peter Slížik
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Slížik @ 2020-09-24  9:55 UTC (permalink / raw)
  To: zsugabubus; +Cc: zsh-users

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

>
>
> function insert-single-quotes() {
>   LBUFFER+="'"
>   RBUFFER="'$RBUFFER"
> }
>

Yes, this would be the best way. I wonder why I overlooked this possibility.
Thanks a lot,
Peter

[-- Attachment #2: Type: text/html, Size: 471 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-24  9:55   ` Peter Slížik
@ 2020-09-25 14:19     ` Peter Slížik
  2020-09-25 14:43       ` Peter Stephenson
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Slížik @ 2020-09-25 14:19 UTC (permalink / raw)
  To: zsugabubus; +Cc: zsh-users

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

By the way, the documentation says that zle -R should be called after
changing the command line from within a ZLE widget.

> Redisplay the command line; this is to be called from within a
user-defined widget to allow changes to become visible.

However, when playing with LBUFFER and RBUFFER I realized that zle -R is
not needed and the changes are visible immediately.

Why is it so?

Peter

чет, 24. сеп 2020. у 11:55 Peter Slížik <peter.slizik@gmail.com> је
написао/ла:

>
>> function insert-single-quotes() {
>>   LBUFFER+="'"
>>   RBUFFER="'$RBUFFER"
>> }
>>
>
> Yes, this would be the best way. I wonder why I overlooked this
> possibility.
> Thanks a lot,
> Peter
>

[-- Attachment #2: Type: text/html, Size: 1348 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-25 14:19     ` Peter Slížik
@ 2020-09-25 14:43       ` Peter Stephenson
  2020-09-26  9:27         ` Daniel Shahaf
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2020-09-25 14:43 UTC (permalink / raw)
  To: zsh-users


> On 25 September 2020 at 15:19 Peter Slížik <peter.slizik@gmail.com> wrote:
> By the way, the documentation says that zle -R should be called after
> changing the command line from within a ZLE widget.
>
> However, when playing with LBUFFER and RBUFFER I realized that zle -R is
> not needed and the changes are visible immediately.
> 
> Why is it so?

You only need to call zle -R either if you are passing it an argument
to show, or if you are bypassing the editor interface somehow so it
doesn't know the display has changed.  If you use any of the special
variables or a zle command to update the command line then ZLE's
internals are all consistent and you don't need any special action.

pws


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-25 14:43       ` Peter Stephenson
@ 2020-09-26  9:27         ` Daniel Shahaf
  2020-09-26  9:40           ` Roman Perepelitsa
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Shahaf @ 2020-09-26  9:27 UTC (permalink / raw)
  To: Peter Slížik; +Cc: zsh-users

Peter Stephenson wrote on Fri, 25 Sep 2020 15:43 +0100:
> > On 25 September 2020 at 15:19 Peter Slížik <peter.slizik@gmail.com> wrote:
> > By the way, the documentation says that zle -R should be called after
> > changing the command line from within a ZLE widget.
> >
> > However, when playing with LBUFFER and RBUFFER I realized that zle -R is
> > not needed and the changes are visible immediately.
> > 
> > Why is it so?  
> 
> You only need to call zle -R either if you are passing it an argument
> to show, or if you are bypassing the editor interface somehow so it
> doesn't know the display has changed.  If you use any of the special
> variables or a zle command to update the command line then ZLE's
> internals are all consistent and you don't need any special action.

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 84be010e1..885366c8c 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -502,7 +502,8 @@ ifnzman(noderef(Completion Widgets))\
 )
 item(tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])(
 Redisplay the command line; this is to be called from within a user-defined
-widget to allow changes to become visible.  If a var(display-string) is
+widget to allow changes made directly to the terminal (bypassing ZLE) to become
+visible.  If a var(display-string) is
 given and not empty, this is shown in the status line (immediately
 below the line being edited).
 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-26  9:27         ` Daniel Shahaf
@ 2020-09-26  9:40           ` Roman Perepelitsa
  2020-09-26 10:24             ` Daniel Shahaf
  0 siblings, 1 reply; 13+ messages in thread
From: Roman Perepelitsa @ 2020-09-26  9:40 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Peter Slížik, Zsh Users

On Sat, Sep 26, 2020 at 11:27 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
>  Redisplay the command line; this is to be called from within a user-defined
> -widget to allow changes to become visible.  If a var(display-string) is
> +widget to allow changes made directly to the terminal (bypassing ZLE) to become
> +visible.  If a var(display-string) is
>  given and not empty, this is shown in the status line (immediately
>  below the line being edited).

I think the original documentation was correct. Consider this snippet:

    function a() {
      BUFFER+='foo'
      zle -R
      sleep 1
      BUFFER+='bar'
    }
    zle -N a
    bindkey '^A' a

    function b() {
      BUFFER+='foo'
      sleep 1
      BUFFER+='bar'
    }
    zle -N b
    bindkey '^B' b

If you press Ctrl+A, "foo" will appear immediately, followed by "bar"
after one second. However, if you press Ctrl+B, "foobar" will appear
after one second. The only difference between the two widgets is that
the first invokes `zle -R` after appending "foo" to BUFFER but the
second doesn't.

Roman.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-26  9:40           ` Roman Perepelitsa
@ 2020-09-26 10:24             ` Daniel Shahaf
  2020-09-26 10:31               ` Roman Perepelitsa
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Shahaf @ 2020-09-26 10:24 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: Peter Slížik, Zsh Users

Roman Perepelitsa wrote on Sat, 26 Sep 2020 11:40 +0200:
> On Sat, Sep 26, 2020 at 11:27 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> >
> >  Redisplay the command line; this is to be called from within a user-defined
> > -widget to allow changes to become visible.  If a var(display-string) is
> > +widget to allow changes made directly to the terminal (bypassing ZLE) to become
> > +visible.  If a var(display-string) is
> >  given and not empty, this is shown in the status line (immediately
> >  below the line being edited).  
> 
> I think the original documentation was correct. Consider this snippet:

Good point.  However, the language "this is to be called … to allow
changes to become visible" does support Peter's interpretation that «zle
-R» must be called for changes to be shown, so I still think there's
room for clarification.

How about:

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 84be010e1..c71aa463e 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -501,8 +501,7 @@ ifnzman(noderef(Completion Widgets))\
 .
 )
 item(tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])(
-Redisplay the command line; this is to be called from within a user-defined
-widget to allow changes to become visible.  If a var(display-string) is
+Redisplay the command line.  If a var(display-string) is
 given and not empty, this is shown in the status line (immediately
 below the line being edited).
 
@@ -511,9 +510,9 @@ prompt in the same way as completion lists are printed. If no
 var(string)s are given but the tt(-c) option is used such a list is
 cleared.
 
-Note that this option is only useful for widgets that do not exit
-immediately after using it because the strings displayed will be erased 
-immediately after return from the widget.
+Note that immediately after returning from running widgets, the command line
+will be redisplayed and the strings displayed will be erased.  Therefore, this
+option is only useful for widgets that do not exit immediately after using it.
 
 This command can safely be called outside user defined widgets; if zle is
 active, the display will be refreshed, while if zle is not active, the


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: How to avoid infinite recursion in ZLE widgets
  2020-09-26 10:24             ` Daniel Shahaf
@ 2020-09-26 10:31               ` Roman Perepelitsa
  0 siblings, 0 replies; 13+ messages in thread
From: Roman Perepelitsa @ 2020-09-26 10:31 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Peter Slížik, Zsh Users

On Sat, Sep 26, 2020 at 12:24 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Roman Perepelitsa wrote on Sat, 26 Sep 2020 11:40 +0200:
> >
> > I think the original documentation was correct. Consider this snippet:
>
> Good point.  However, the language "this is to be called … to allow
> changes to become visible" does support Peter's interpretation that «zle
> -R» must be called for changes to be shown, so I still think there's
> room for clarification.

LGTM.

Roman.


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-09-26 10:32 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-23  8:34 How to avoid infinite recursion in ZLE widgets Peter Slížik
2020-09-23 11:21 ` Peter Stephenson
2020-09-23 11:24   ` Peter Slížik
2020-09-23 11:29 ` Daniel Shahaf
2020-09-23 11:32   ` Peter Slížik
2020-09-23 18:25 ` zsugabubus
2020-09-24  9:55   ` Peter Slížik
2020-09-25 14:19     ` Peter Slížik
2020-09-25 14:43       ` Peter Stephenson
2020-09-26  9:27         ` Daniel Shahaf
2020-09-26  9:40           ` Roman Perepelitsa
2020-09-26 10:24             ` Daniel Shahaf
2020-09-26 10:31               ` Roman Perepelitsa

zsh-users

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://inbox.vuxu.org/zsh-users

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 zsh-users zsh-users/ http://inbox.vuxu.org/zsh-users \
		zsh-users@zsh.org
	public-inbox-index zsh-users

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.zsh.users


code repositories for the project(s) associated with this inbox:

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

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git