zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps
@ 2016-12-12 15:39 Teubel György
  2016-12-13  1:27 ` Frank Terbeck
  0 siblings, 1 reply; 3+ messages in thread
From: Teubel György @ 2016-12-12 15:39 UTC (permalink / raw)
  To: zsh-workers

Make Home, End and Delete keys work by default as expected by most users.
---
 Doc/Zsh/zle.yo       | 12 ++++++------
 Src/Zle/zle_keymap.c | 11 +++++++++--
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index d68365b94..4d2c8580c 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -1231,12 +1231,12 @@ item(tt(vi-backward-word-end) (unbound) (tt(ge)) (unbound))(
 Move to the end of the previous word, vi-style.
 )
 tindex(beginning-of-line)
-item(tt(beginning-of-line) (tt(^A)) (unbound) (unbound))(
+item(tt(beginning-of-line) (tt(^A) tt(ESC-[1~)) (unbound) (unbound))(
 Move to the beginning of the line.  If already at the beginning
 of the line, move to the beginning of the previous line, if any.
 )
 tindex(vi-beginning-of-line)
-item(tt(vi-beginning-of-line))(
+item(tt(vi-beginning-of-line) (unbound) (tt(ESC-[1~)) (tt(ESC-[1~)))(
 Move to the beginning of the line, without changing lines.
 )
 tindex(down-line)
@@ -1244,12 +1244,12 @@ item(tt(down-line) (unbound) (unbound) (unbound))(
 Move down a line in the buffer.
 )
 tindex(end-of-line)
-item(tt(end-of-line) (tt(^E)) (unbound) (unbound))(
+item(tt(end-of-line) (tt(^E) tt(ESC-[4~)) (unbound) (unbound))(
 Move to the end of the line.  If already at the end
 of the line, move to the end of the next line, if any.
 )
 tindex(vi-end-of-line)
-item(tt(vi-end-of-line) (unbound) (tt($)) (unbound))(
+item(tt(vi-end-of-line) (unbound) (tt($) tt(ESC-[4~)) (tt(ESC-[4~)))(
 Move to the end of the line.
 If an argument is given to this command, the cursor will be moved to
 the end of the line (argument - 1) lines down.
@@ -1778,11 +1778,11 @@ from the cursor position to the endpoint of the movement.
 If the command is tt(vi-delete), kill the current line.
 )
 tindex(delete-char)
-item(tt(delete-char))(
+item(tt(delete-char) (tt(ESC-[3~)) (unbound) (unbound))(
 Delete the character under the cursor.
 )
 tindex(vi-delete-char)
-item(tt(vi-delete-char) (unbound) (tt(x)) (unbound))(
+item(tt(vi-delete-char) (unbound) (tt(x) tt(ESC-[3~)) (tt(ESC-[3~)))(
 Delete the character under the cursor,
 without going past the end of the line.
 )
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 04eb70675..cff044237 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1342,11 +1342,15 @@ default_bindings(void)
     vimaps[1] = amap;
     for (i = 0; i < 2; i++) {
 	kptr = vimaps[i];
-	/* vi command and insert modes: arrow keys */
+	/* vi command and insert modes: arrow keys,
+	 * home, end and delete */
 	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');
+	bindkey(kptr, "\033[1~", refthingy(t_vibeginningofline), NULL);
+	bindkey(kptr, "\033[4~", refthingy(t_viendofline), NULL);
+	bindkey(kptr, "\033[3~", refthingy(t_videletechar), NULL);
     }
     vilmaps[0] = oppmap;
     vilmaps[1] = vismap;
@@ -1386,11 +1390,14 @@ default_bindings(void)
     bindkey(amap, "guu", NULL, "gugu");
     bindkey(amap, "gUU", NULL, "gUgU");
 
-    /* emacs mode: arrow keys */ 
+    /* emacs mode: arrow keys, home, end and delete */
     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');
+    bindkey(emap, "\033[1~", refthingy(t_beginningofline), NULL);
+    bindkey(emap, "\033[4~", refthingy(t_endofline), NULL);
+    bindkey(emap, "\033[3~", refthingy(t_deletechar), NULL);
    
     /* emacs mode: ^X sequences */
     bindkey(emap, "\30*",   refthingy(t_expandword), NULL);
-- 
2.11.0


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

* Re: [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps
  2016-12-12 15:39 [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps Teubel György
@ 2016-12-13  1:27 ` Frank Terbeck
  2016-12-13 10:36   ` Teubel György
  0 siblings, 1 reply; 3+ messages in thread
From: Frank Terbeck @ 2016-12-13  1:27 UTC (permalink / raw)
  To: Teubel György; +Cc: zsh-workers

Hi.

Teubel György wrote:
> Make Home, End and Delete keys work by default as expected by most users.
[...]
> +item(tt(beginning-of-line) (tt(^A) tt(ESC-[1~)) (unbound) (unbound))(

Unfortunately, it's not that easy. Those special keys are not stable,
even across a small sample of terminals and terminal emulators. You'd
have to take a look at termcap or terminfo to get a reasonably well
founded escape sequence for them, which also requires the terminal to be
in smkx mode, while the line editor is active.

Zsh does have a terminfo module and it can be used to set up some well
known special keys. But those are best added to a global configuration
file, rather than being hard coded in C. This is what Debian does¹ for
example.


Regards, Frank

¹ https://anonscm.debian.org/cgit/collab-maint/zsh.git/tree/debian/zshrc

-- 
In protocol design, perfection has been reached not when there is
nothing left to add, but when there is nothing left to take away.
                                                  -- RFC 1925


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

* Re: [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps
  2016-12-13  1:27 ` Frank Terbeck
@ 2016-12-13 10:36   ` Teubel György
  0 siblings, 0 replies; 3+ messages in thread
From: Teubel György @ 2016-12-13 10:36 UTC (permalink / raw)
  To: zsh-workers

On Tue, Dec 13, 2016 at 02:27:57AM +0100, Frank Terbeck wrote:
> Teubel György wrote:
> > Make Home, End and Delete keys work by default as expected by most users.
> [...]
> > +item(tt(beginning-of-line) (tt(^A) tt(ESC-[1~)) (unbound) (unbound))(
> 
> Unfortunately, it's not that easy. Those special keys are not stable,
> even across a small sample of terminals and terminal emulators. You'd
> have to take a look at termcap or terminfo to get a reasonably well
> founded escape sequence for them, which also requires the terminal to be
> in smkx mode, while the line editor is active.

You are right, it should be done by querying termcap capabilities.  Here is a
modified version of the patch.  I used a tighter version of the add_cursor_key()
function.  In addition, the Insert key is bound to 'vi-insert' in vi command mode.

> Zsh does have a terminfo module and it can be used to set up some well
> known special keys. But those are best added to a global configuration
> file, rather than being hard coded in C. This is what Debian does¹ for
> example.

I know that there is a terminfo (and a termcap) module.  The difference is that
when it is in the default bindings (as the arrow keys are, for example), then these
keys work out of the box, without additional configuration.  This increases user
experience a bit.

> Regards, Frank

---
 Doc/Zsh/zle.yo       | 14 +++++++-------
 Src/Zle/zle_keymap.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 Src/init.c           |  3 ++-
 Src/zsh.h            |  6 +++++-
 4 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index d68365b94..18a73b416 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -1231,12 +1231,12 @@ item(tt(vi-backward-word-end) (unbound) (tt(ge)) (unbound))(
 Move to the end of the previous word, vi-style.
 )
 tindex(beginning-of-line)
-item(tt(beginning-of-line) (tt(^A)) (unbound) (unbound))(
+item(tt(beginning-of-line) (tt(^A) tt(HOME)) (unbound) (unbound))(
 Move to the beginning of the line.  If already at the beginning
 of the line, move to the beginning of the previous line, if any.
 )
 tindex(vi-beginning-of-line)
-item(tt(vi-beginning-of-line))(
+item(tt(vi-beginning-of-line) (unbound) (tt(HOME)) (tt(HOME)))(
 Move to the beginning of the line, without changing lines.
 )
 tindex(down-line)
@@ -1244,12 +1244,12 @@ item(tt(down-line) (unbound) (unbound) (unbound))(
 Move down a line in the buffer.
 )
 tindex(end-of-line)
-item(tt(end-of-line) (tt(^E)) (unbound) (unbound))(
+item(tt(end-of-line) (tt(^E) tt(END)) (unbound) (unbound))(
 Move to the end of the line.  If already at the end
 of the line, move to the end of the next line, if any.
 )
 tindex(vi-end-of-line)
-item(tt(vi-end-of-line) (unbound) (tt($)) (unbound))(
+item(tt(vi-end-of-line) (unbound) (tt($) tt(END)) (tt(END)))(
 Move to the end of the line.
 If an argument is given to this command, the cursor will be moved to
 the end of the line (argument - 1) lines down.
@@ -1778,11 +1778,11 @@ from the cursor position to the endpoint of the movement.
 If the command is tt(vi-delete), kill the current line.
 )
 tindex(delete-char)
-item(tt(delete-char))(
+item(tt(delete-char) (tt(DELETE)) (unbound) (unbound))(
 Delete the character under the cursor.
 )
 tindex(vi-delete-char)
-item(tt(vi-delete-char) (unbound) (tt(x)) (unbound))(
+item(tt(vi-delete-char) (unbound) (tt(x) tt(DELETE)) (tt(DELETE)))(
 Delete the character under the cursor,
 without going past the end of the line.
 )
@@ -1814,7 +1814,7 @@ item(tt(vi-indent) (unbound) (tt(>)) (unbound))(
 Indent a number of lines.
 )
 tindex(vi-insert)
-item(tt(vi-insert) (unbound) (tt(i)) (unbound))(
+item(tt(vi-insert) (unbound) (tt(i) tt(INSERT)) (unbound))(
 Enter insert mode.
 )
 tindex(vi-insert-bol)
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 04eb70675..c6b6bdc0a 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1280,6 +1280,38 @@ add_cursor_key(Keymap km, int tccode, Thingy thingy, int defchar)
     }
 }
 
+/* interrogate termcap for special keys and add binding to keymap */
+
+/**/
+static void
+bind_termcap_key(Keymap km, int tccode, Thingy thingy)
+{
+    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';
+
+	/*
+	 * Sanity checking.  If the key is zero-length (unlikely,
+	 * but this is termcap we're talking about), or it's a single
+	 * character, then we don't bind it.
+	 */
+	if (buf[0] && buf[1] && (buf[0] != Meta || buf[2])) {
+	    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.    */
@@ -1342,12 +1374,20 @@ default_bindings(void)
     vimaps[1] = amap;
     for (i = 0; i < 2; i++) {
 	kptr = vimaps[i];
-	/* vi command and insert modes: arrow keys */
+	/* vi command and insert modes: arrow keys,
+	 * home, end and delete */
 	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');
+	bind_termcap_key(kptr, TCHOMEKEY, refthingy(t_vibeginningofline));
+	bind_termcap_key(kptr, TCENDKEY, refthingy(t_viendofline));
+	bind_termcap_key(kptr, TCDELETEKEY, refthingy(t_videletechar));
     }
+
+    /* Insert key enters insert mode */
+    bind_termcap_key(amap, TCINSERTKEY, refthingy(t_viinsert));
+
     vilmaps[0] = oppmap;
     vilmaps[1] = vismap;
     for (i = 0; i < 2; i++) {
@@ -1386,11 +1426,14 @@ default_bindings(void)
     bindkey(amap, "guu", NULL, "gugu");
     bindkey(amap, "gUU", NULL, "gUgU");
 
-    /* emacs mode: arrow keys */ 
+    /* emacs mode: arrow keys, home, end and delete */
     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');
+    bind_termcap_key(emap, TCHOMEKEY, refthingy(t_beginningofline));
+    bind_termcap_key(emap, TCENDKEY, refthingy(t_endofline));
+    bind_termcap_key(emap, TCDELETEKEY, refthingy(t_deletechar));
    
     /* emacs mode: ^X sequences */
     bindkey(emap, "\30*",   refthingy(t_expandword), NULL);
diff --git a/Src/init.c b/Src/init.c
index c12043b88..7b632394e 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -670,7 +670,8 @@ 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",
-    "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB"
+    "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB",
+    "kh", "@7", "kD", "kI"
 };
 
 /**/
diff --git a/Src/zsh.h b/Src/zsh.h
index f22d8b135..6f6544d09 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2524,7 +2524,11 @@ struct ttyinfo {
 #define TCBACKSPACE    31
 #define TCFGCOLOUR     32
 #define TCBGCOLOUR     33
-#define TC_COUNT       34
+#define TCHOMEKEY      34
+#define TCENDKEY       35
+#define TCDELETEKEY    36
+#define TCINSERTKEY    37
+#define TC_COUNT       38
 
 #define tccan(X) (tclen[X])
 
-- 
2.11.0


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

end of thread, other threads:[~2016-12-13 16:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-12 15:39 [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps Teubel György
2016-12-13  1:27 ` Frank Terbeck
2016-12-13 10:36   ` Teubel György

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).