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

Re: Key bindings in Zsh?

I hope you don't mind that I've Cc'd this to zsh-users.  Having taken as
long as I did to write it, I'd rather it get seen by more people who might
be interested.

On Sep 1,  2:01pm, Brian P. Barnes wrote:
> Subject: Re: Key bindings in Zsh?
> For something as simple as editing a command on the command line, I hate
> having to use vi commands.

I'm not sure what vi has to do with this, unless you mean that you use the
vi mode keybindings in zsh rather than the emacs ones.  You should mention
these details when you send questions.

> I just use word processor type editing. It's nice
> if the home takes you to the start of the command. Right now, I have that
> function to the next key over, page-up, because I just get a beep from the
> home key. Similarly, end should send you to the end of the command. Insert
> should toggle insert/overwrite mode.

The example bindkey commands I included should have set that up (for emacs
keybindings).  If you're using the vi bindings, then it's trickier, because
of the special handling of ESC to switch from insert to command modes.

> Delete should delete the character over
> the cursor (not backspace over the previous character).

Not all word processors do that; in fact, the most common Unix editors
e.g. emacs and the original vi do not; the original vi mapped backspace
and delete to the same thing when the terminal driver erase key was
bound to delete, and simply beeped at the delete key when the terminal
driver erase was bound to backspace.

Further, not everyone has a PC-101 keyboard, and people are more used to
touch-typing than to looking at the labels on their keycaps, so it's nice
(for most of us) not to be surprised when the key at the upper right of
the main alphabetic key area happens not to say "Backspace".

There is no "right way" that zsh could preconfigure this; somebody would
complain no matter what.  That's why there's "bindkey" and why zsh reads
all those init files.

> It would be cool if pageup/pagedown scrolled the contents of the zsh window
> up or down just like dragging the scroll bar does. I used to use an HP-9000
> that was setup that way and it was very handy.

Are you using a Linux console or an xterm window?  If so, try shift-pageup
and shift-pagedown.

Note, however, that zsh is not interpreting those keystrokes.  You seem to
have a misunderstanding of the way shells and terminal emulators work.  It
is the terminal emulator that captures all the output and lets you scroll
back through it, not zsh, and there's no way for zsh to receive a key and
then tell the emulator to scroll its buffer.  Instead you have to make the
emulator capture the key without ever sending it to zsh, and respond by
scrolling the buffer (note that the insertion point cursor does not move
when this happens).  This means, for example, changing the resources for
your xterm, not adding bindings to zsh.

When you're running an editor like VIM, the situation is different.  Now
the editor really is buffering all the text, and can scroll back and forth
through it and move the insertion point arbitrarily.  Zsh does this when
(and only when) you are editing a command line; once the command begins
executing, zsh gets completely out of the way and lets the command write
directly to the terminal and read directly from it.  If it didn't do this,
commands like VIM that want to draw their own output all over the screen
would compete with the shell for control of what the screen looks like.

HP-9000 terminals, by the way, are a weird case where the terminal does
seem to move the insertion cursor around, but only programs that have been
specially designed to work with HP terminals can figure out where the input
is actually going.  This is a holdover from mainframe computer days where
a single huge computer had hundreds of identical terminals all bought from
the same vendor.  (Can you say AS/400?)

> I did find some documentation on bindkey and fixed a few of the mapping
> issues myself. The ones I can't figure out are the ones that just beep or
> give a ~.  If I assign the ~ to some useful function, Insert, pgup, pgdn,
> which all give squiggles, would all do the same thing.

This is almost certainly because you are using vi mode mappings.  What is
really happening when you press those keys is that zsh receives the a
sequence of characters that begins with an ESC.  This kicks you out of vi
insert mode and into command mode; the rest of the sequence is then taken
as vi commands.

You need to use "bindkey -v ..." and include the entire escape sequence
to get this to work right.  Try this:  On the command line, first type
control-v (which usually means "quote the next character").  Then press
one of those keys that beeps at you.  You'll probably see ^[q56~ or some
such; the ^[ means ESC.  So then you use

	bindkey -v '\eq56~' vi-beginning-of-line

(or whatever, I'm imagining Home is what sends that sequence).  Repeat for
whatever other keys you want bound.

> VIM handles every key exactly as labeled as does every other modern
> (non-curses, non-vm) interface I use, except for Zsh.

I don't know what you mean by "non-vm" but zsh *is* in effect a curses
interface.  So is VIM, actually, unless you're running the X11 version that
starts its own window.

A native X11 program like xedit or Netscape or xterm receives a single X
"event" for every key you press.  This "event" includes a complete state
of the keyboard, i.e., which of the right/left control/shift/alt/meta keys
were held down, whether caps-lock is on, etc.  The X11 application then
decides what to do with that event.  In the case of xterm, what it does
is consult a mapping table that translates the event into a series of
characters (bytes), and then sends those bytes to the program running
inside the xterm, exactly as if you had typed them directly.  For keys
like a, b, c, ... or shift-A, shift-B, shift-C, ... a single ASCII byte is
normally sent ('a', 'b', 'c', ..., 'A', 'B', 'C', ...).  For function keys
like insert, home, pageup, F11, etc. a _sequence_ of bytes is sent; e.g.
on an xterm, pageup normally sends ESC, '[', '5', '~'.  An aixterm does
the same thing, but sends different sequences for the same keys.

Many of the combinations of control/alt/meta with other keys simply have
no mapping at all in the xterm or aixterm tables.  In those cases, either
the emulator sends nothing at all to the program running inside it, or
the unknown modifier keys are thrown away until it finds something it
does recognize and then the sequence for that is sent.  So it often is
completely impossible to bind zsh actions to certain key combinations,
because the terminal emulator can't or won't tell zsh exactly what keys
were pressed.

What editors like VIM do is use a database called "termcap" or another
one called "terminfo" (depends on what's installed) to reverse-map the
sequnces of bytes *back* to the corresponding keys again.  Such editors
also send special "terminal initialization" sequences to be sure that
the terminal emulator is in the correct state before they begin to get
input from it, and similar sequences to restore the previous state when
they are finished.  Zsh could be modified to look up the initialization
sequences and reverse mappings and set up the terminal just like an
editor; but it's a lot of overhead and much more easily accomplished by
personalized bindkey commands, given the inevitable disagreement about
exactly how "a word processor" behaves.

Good luck with your keybindings.

Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

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