zsh-users
 help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: zsh-users@sunsite.dk
Subject: Rebinding a widget within a keymap
Date: Sat, 29 Jul 2006 23:29:39 -0700	[thread overview]
Message-ID: <060729232941.ZM12664@torch.brasslantern.com> (raw)

The zsh bindkey and zle commands allow one to do most things one might
want to do with keymaps, such as copying one, setting bindings, etc.
However, there isn't a straightforward way to express transformations
such as "temporarily change all keys bound to 'self-insert' to instead
be bound to 'frob'".

This leads to workarounds such as

	zle -N self-insert frob
	zle recursive-edit
	zle -A .self-insert self-insert

This is unsatisfactory, as it's sometimes difficult to guarantee that
the "zle -A" step occurs; and if it doesn't, you're left frobbing in
a context where you should be inserting.  Furthermore, this fails if
self-insert was previously replaced by yet some other widget, so to get
that handled properly it's necessary to do

	zle -A self-insert saved-self-insert
	zle -N self-insert frob
	zle recursive-edit
	zle -A saved-self-insert self-insert
	zle -D saved-self-insert

This introduces possible name clashes on saved-self-insert; e.g., it
can't be invoked again from inside recursive-edit, and every added bit
of code to repair such a problem makes the unwinding more precarious.
Automatically saving and restoring keymaps with

	bindkey -N frobber main
	zle recursive-edit -K frobber

was meant to help with this, but without doing some sort of processing
on $(bindkey -L) it's not possible to determine which keys are already
bound to self-insert and thus need rebinding in frobber, and we're back
where we started.

Having given you all that background, I'm obviously about to propose a
solution.  Here it is.

  zmodload -i zsh/zleparameter

  for k in $keymaps
  do
    if (( $+widgets[self-insert-$k] == 0 ))
    then zle -A self-insert self-insert-$k
    fi
  done

  self-insert-by-keymap() {
    if (( $+widgets[$WIDGET-$KEYMAP] == 1 ))
    then zle $WIDGET-$KEYMAP "$@"
    else zle .$WIDGET "$@"
    fi
  }
  zle -N self-insert self-insert-by-keymap

This can of course be extended to any/all other widgets; just put a loop
"for w in ${(k)widgets}" around the whole thing and replace "self-insert"
with "$w" throughout.  (It's at that point that the lack of control over
autoremoval, which I've mentioned in other threads, becomes an issue, so
if you want to go beyond self-insert you'll have to write it out yourself.)

With this in place, you should rarely need "zle -N self-insert frob" again.
Instead you do this:

	bindkey -N frobber main
	zle -N self-insert-frobber frob

Then, whenever you wish to replace self-insert with frob, change keymaps:

	zle recursive-edit -K frobber

Here's a simple example, which improves upon the caps-lock example in the
zsh manual entry for recursive-edit:

  # Assumes self-insert-by-keymap installed as self-insert!

  self-insert-ucase() {
    LBUFFER+=${(U)KEYS[-1]}
  }
  zle -N self-insert-ucase
  caps-lock() {
    bindkey -N ucase $KEYMAP
    bindkey -M ucase "$KEYS" .accept-line
    zle recursive-edit -K ucase || zle send-break
  }
  zle -N caps-lock

To turn this on, pick a key sequence (I've chosen ctrl-x shift-L) and
bind the caps-lock widget to it:

  bindkey -M main '^XL' caps-lock

An obvious extension to this scheme is to create a variant of accept-line
that notifies the caller of recursive-edit as to whether it should treat
the end of the recursive-edit as final acceptance of the buffer, so that
it's possible e.g. to execute a command without first explicitly leaving
caps-lock "mode".

The other remaining drawback to this scheme is that it can't be employed
at the topmost level of ZLE, because the value of $KEYMAP is always "main"
(or "vicmd" as a special case) at that level.

Note that for builtin widgets the "for k in $keymaps" loop is extraneous;
so it would be possible to embed this widget-name-by-keymap logic in the
C code in ZLE, thereby making it possible to insert an "override" widget
into any specific keymap simply by creating a new widget with the keymap
name appended.  Old code that uses "zle -N builtin-widget user-function"
would continue to work, but would break new code that relies on the by-
keymap technique.

-- 


             reply	other threads:[~2006-07-30  6:30 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <schaefer@brasslantern.com>
2006-07-30  6:29 ` Bart Schaefer [this message]
2006-07-30 17:18   ` Peter Stephenson
2006-07-30 17:46     ` Bart Schaefer
2006-09-04  8:43 Solved, but now a new twist (was: Double Evaluation Question (not in FAQ)) Com MN PG P E B Consultant 3
2006-09-04 18:24 ` Bart Schaefer
2006-09-07 17:53   ` Peter Stephenson
2006-10-06 15:07 Move command line options to start of line Peter Stephenson
2006-10-07  2:55 ` Bart Schaefer
2006-10-07  6:20   ` Andrey Borzenkov
2006-10-07 12:02   ` Peter Stephenson
2006-10-07 12:39     ` Bart Schaefer
2006-10-07 17:21       ` Dan Nelson
2006-10-07 17:36       ` Peter Stephenson
2007-03-31 20:51 Documentation of colon in parameter expansion Miciah Dashiel Butler Masters
2007-04-01 17:53 ` Bart Schaefer
2007-04-01 18:26   ` Peter Stephenson
2007-09-02 15:43 fg jobs info Atom Smasher
2007-09-02 17:59 ` Bart Schaefer
2007-09-03  7:38   ` Stephane Chazelas
2007-09-03 15:58     ` Bart Schaefer
2007-09-03 16:31   ` Matthew Wozniski
2007-09-04 11:16   ` Atom Smasher
2007-09-04 15:31     ` Bart Schaefer
2007-09-04 20:38       ` Peter Stephenson
2007-09-04 20:45       ` Peter Stephenson
2007-09-05  9:02       ` Atom Smasher
2007-09-05  9:28         ` Peter Stephenson
2007-09-05 11:21           ` Miek Gieben
2007-09-05 11:34             ` Matthew Wozniski
2007-09-05 11:36               ` Miek Gieben
2007-09-05 11:34             ` Atom Smasher
2007-09-05 11:40             ` Frank Terbeck
2007-09-05 12:18               ` Miek Gieben
2007-09-05 15:30           ` Bart Schaefer
2007-09-05 15:55             ` Peter Stephenson
2007-09-05 16:34 preexec hook: possible enhancement? Matthew Wozniski
2007-09-05 17:14 ` Bart Schaefer
2007-09-05 19:05   ` Peter Stephenson
2007-09-05 21:11     ` Matthew Wozniski
2007-09-08 17:20     ` Bart Schaefer
2007-09-05 19:32 ` Stephane Chazelas
     [not found] <1209745744.25440.ezmlm@sunsite.dk>
2008-05-02 17:39 ` Zsh hangs sometimes? Kamil Jońca
2008-05-02 22:44   ` Peter Stephenson
2008-05-03 11:35     ` Bart Schaefer
2008-05-04 12:13       ` Peter Stephenson
2008-05-04 17:00         ` Bart Schaefer
2008-05-04 18:14           ` Peter Stephenson
2008-05-04 20:00             ` Bart Schaefer
2008-05-05 11:54               ` Aaron Davies
2010-08-20 15:35 Synchronous vs. Asynchronous Bart Schaefer
2010-08-20 15:45 ` Peter Stephenson
2010-08-20 17:36   ` Bart Schaefer
2010-08-21 18:41     ` Peter Stephenson
2010-08-21 22:31       ` Vincent Lefevre
2010-08-22  5:02         ` Bart Schaefer
2010-08-22  5:42       ` Bart Schaefer
2010-08-22 17:53         ` Peter Stephenson
2013-08-30  1:12 mailcap configuration in zsh can't open .bk files vinurs
2013-08-30  2:59 ` Phil Pennock
2013-08-30  3:27   ` shawn wilson
2013-08-30  8:29   ` Peter Stephenson
2013-08-30 17:10     ` Bart Schaefer
2013-09-01 17:11       ` Peter Stephenson
2013-09-02  1:28         ` vinurs
2013-09-02 13:46           ` Peter Stephenson
2013-09-02 17:45             ` 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=060729232941.ZM12664@torch.brasslantern.com \
    --to=schaefer@brasslantern.com \
    --cc=zsh-users@sunsite.dk \
    /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).