about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/zle.yo18
-rw-r--r--Src/Zle/zle_keymap.c86
-rw-r--r--Src/init.c3
-rw-r--r--Src/zsh.h6
5 files changed, 95 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c245ceb9..2892a2307 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2001-03-13  Peter Stephenson  <pws@csr.com>
+
+	* 13611, 13615: Doc/Zsh/zle.yo, Src/init.c, Src/zsh.h, 
+	Src/Zle/zle_keymap.c: Use termcap to find cursor sequences to
+	bind; default to VT100.  If ^[[? or ^[O? is being bound, bind
+	the other one too.  Also bind cursor keys in viins keymap.
+
 2001-03-12  Oliver Kiddle  <opk@zsh.org>
 
 	* 13610: INSTALL, README, Completion/Core/compinit,
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 02a828c4f..e0c13da72 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -201,6 +201,16 @@ The following is a list of all the standard widgets,
 and their default bindings in emacs mode,
 vi command mode and vi insert mode
 (the `tt(emacs)', `tt(vicmd)' and `tt(viins)' keymaps, respectively).
+
+Note that cursor keys are bound to movement keys in all three keymaps;
+the shell assumes that the cursor keys send the key sequences reported
+by the terminal-handling library (termcap or terminfo).  The key sequences
+shown in the list are those based on the VT100, common on many modern
+terminals, but in fact these are not necessarily bound.  In the case of the
+tt(viins) keymap, the initial escape character of the sequences serves also
+to return to the tt(vicmd) keymap: whether this happens is determined by
+the tt(KEYTIMEOUT) parameter, see ifzman(zmanref(zshparam))\
+ifnzman(noderef(Parameters)).
 startmenu()
 menu(Movement)
 menu(History Control)
@@ -222,7 +232,7 @@ item(tt(backward-char) (^B ESC-[D) (unbound) (unbound))(
 Move backward one character.
 )
 tindex(vi-backward-char)
-item(tt(vi-backward-char) (unbound) (^H h ^?) (unbound))(
+item(tt(vi-backward-char) (unbound) (^H h ^?) (ESC-[D))(
 Move backward one character, without changing lines.
 )
 tindex(backward-word)
@@ -273,7 +283,7 @@ item(tt(forward-char) (^F ESC-[C) (unbound) (unbound))(
 Move forward one character.
 )
 tindex(vi-forward-char)
-item(tt(vi-forward-char) (unbound) (space l) (unbound))(
+item(tt(vi-forward-char) (unbound) (space l) (ESC-[C))(
 Move forward one character.
 )
 tindex(vi-find-next-char)
@@ -357,7 +367,7 @@ item(tt(beginning-of-history))(
 Move to the first event in the history list.
 )
 tindex(down-line-or-history)
-item(tt(down-line-or-history) (^N ESC-[B) (j) (unbound))(
+item(tt(down-line-or-history) (^N ESC-[B) (j) (ESC-[B))(
 Move down a line in the buffer, or if already at the bottom line,
 move to the next event in the history list.
 )
@@ -546,7 +556,7 @@ item(tt(vi-rev-repeat-search) (unbound) (N) (unbound))(
 Repeat the last vi history search, but in reverse.
 )
 tindex(up-line-or-history)
-item(tt(up-line-or-history) (^P ESC-[A) (k) (unbound))(
+item(tt(up-line-or-history) (^P ESC-[A) (k) (ESC-[A))(
 Move up a line in the buffer, or if already at the top line,
 move to the previous event in the history list.
 )
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 28203655e..b46c74f91 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1011,6 +1011,56 @@ cleanup_keymaps(void)
     zfree(keybuf, keybufsz);
 }
 
+static char *cursorptr;
+
+/* utility function for termcap output routine to add to string */
+
+static int 
+add_cursor_char(int c)
+{
+    *cursorptr++ = c;
+    return 0;
+}
+
+/* interrogate termcap for cursor keys and add bindings to keymap */
+
+/**/
+static void
+add_cursor_key(Keymap km, int tccode, Thingy thingy, int defchar)
+{
+    char buf[2048];
+
+    /*
+     * Be careful not to try too hard with bindings for dubious or
+     * dysfunctional terminals.
+     */
+    if (tccan(tccode) && !(termflags & (TERM_NOUP|TERM_BAD|TERM_UNKNOWN))) {
+	/*
+	 * We can use the real termcap sequence.  We need to
+	 * persuade termcap to output `move cursor 1 char' and capture it.
+	 */
+	cursorptr = buf;
+	tputs(tcstr[tccode], 1, add_cursor_char);
+	*cursorptr = '\0';
+    } else {
+	/* Assume the normal VT100-like values. */
+	sprintf(buf, "\33[%c", defchar);
+    }
+    bindkey(km, buf, refthingy(thingy), NULL);
+
+    /*
+     * If the string looked like \e[? or \eO?, bind the other one, too.
+     * This is necessary to make cursor keys work on many xterms with
+     * both normal and application modes.
+     */
+    if (buf[0] == '\33' && (buf[1] == '[' || buf[1] == 'O') && 
+	buf[2] && !buf[3])
+    {
+	buf[1] = (buf[1] == '[') ? 'O' : '[';
+	bindkey(km, buf, refthingy(thingy), NULL);
+    }
+}
+
 /* Create the default keymaps.  For efficiency reasons, this function   *
  * assigns directly to the km->first array.  It knows that there are no *
  * prefix bindings in the way, and that it is using a simple keymap.    */
@@ -1023,6 +1073,7 @@ default_bindings(void)
     Keymap emap = newkeymap(NULL, "emacs");
     Keymap amap = newkeymap(NULL, "vicmd");
     Keymap smap = newkeymap(NULL, ".safe");
+    Keymap vimaps[2], kptr;
     char buf[3], *ed;
     int i;
 
@@ -1066,25 +1117,22 @@ default_bindings(void)
     /* vt100 arrow keys are bound by default, for historical reasons. *
      * Both standard and keypad modes are supported.                  */
 
-    /* vi command mode: arrow keys */
-    bindkey(amap, "\33[A",  refthingy(t_uplineorhistory), NULL);
-    bindkey(amap, "\33[B",  refthingy(t_downlineorhistory), NULL);
-    bindkey(amap, "\33[C",  refthingy(t_viforwardchar), NULL);
-    bindkey(amap, "\33[D",  refthingy(t_vibackwardchar), NULL);
-    bindkey(amap, "\33OA",  refthingy(t_uplineorhistory), NULL);
-    bindkey(amap, "\33OB",  refthingy(t_downlineorhistory), NULL);
-    bindkey(amap, "\33OC",  refthingy(t_viforwardchar), NULL);
-    bindkey(amap, "\33OD",  refthingy(t_vibackwardchar), NULL);
-
-    /* emacs mode: arrow keys */
-    bindkey(emap, "\33[A",  refthingy(t_uplineorhistory), NULL);
-    bindkey(emap, "\33[B",  refthingy(t_downlineorhistory), NULL);
-    bindkey(emap, "\33[C",  refthingy(t_forwardchar), NULL);
-    bindkey(emap, "\33[D",  refthingy(t_backwardchar), NULL);
-    bindkey(emap, "\33OA",  refthingy(t_uplineorhistory), NULL);
-    bindkey(emap, "\33OB",  refthingy(t_downlineorhistory), NULL);
-    bindkey(emap, "\33OC",  refthingy(t_forwardchar), NULL);
-    bindkey(emap, "\33OD",  refthingy(t_backwardchar), NULL);
+    vimaps[0] = vmap;
+    vimaps[1] = amap;
+    for (i = 0; i < 2; i++) {
+	kptr = vimaps[i];
+	/* vi command and insert modes: arrow keys */
+	add_cursor_key(kptr, TCUPCURSOR, t_uplineorhistory, 'A');
+	add_cursor_key(kptr, TCDOWNCURSOR, t_downlineorhistory, 'B');
+	add_cursor_key(kptr, TCLEFTCURSOR, t_vibackwardchar, 'D');
+	add_cursor_key(kptr, TCRIGHTCURSOR, t_viforwardchar, 'C');
+    }
+
+    /* emacs mode: arrow keys */ 
+    add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A');
+    add_cursor_key(emap, TCDOWNCURSOR, t_downlineorhistory, 'B');
+    add_cursor_key(emap, TCLEFTCURSOR, t_backwardchar, 'D');
+    add_cursor_key(emap, TCRIGHTCURSOR, t_forwardchar, 'C');
    
     /* emacs mode: ^X sequences */
     bindkey(emap, "\30*",   refthingy(t_expandword), NULL);
diff --git a/Src/init.c b/Src/init.c
index b07ac80d5..a0c06aa63 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -497,7 +497,8 @@ init_shout(void)
 static char *tccapnams[TC_COUNT] = {
     "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
     "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
-    "md", "so", "us", "me", "se", "ue", "ch"
+    "md", "so", "us", "me", "se", "ue", "ch",
+    "ku", "kd", "kl", "kr"
 };
 
 /* Initialise termcap */
diff --git a/Src/zsh.h b/Src/zsh.h
index baafdb0e6..315c1d3bd 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1524,7 +1524,11 @@ struct ttyinfo {
 #define TCSTANDOUTEND  22
 #define TCUNDERLINEEND 23
 #define TCHORIZPOS     24
-#define TC_COUNT       25
+#define TCUPCURSOR     25
+#define TCDOWNCURSOR   26
+#define TCLEFTCURSOR   27
+#define TCRIGHTCURSOR  28
+#define TC_COUNT       29
 
 #define tccan(X) (tclen[X])