From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6343 invoked by alias); 13 Dec 2016 16:16:01 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 40174 Received: (qmail 18315 invoked from network); 13 Dec 2016 16:16:01 -0000 X-Qmail-Scanner-Diagnostics: from mail-wm0-f48.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.99.2/21882. spamassassin: 3.4.1. Clear:RC:0(74.125.82.48):SA:0(-0.0/5.0):. Processed in 1.89143 secs); 13 Dec 2016 16:16:01 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_PASS, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.1 X-Envelope-From: tgyurci@gmail.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 74.125.82.48 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=TKETJ59J8B0xhNci58EL1G6g4mmnKZDXYUR/sXhVC4c=; b=kxd7LKAFQOLA0KAJPs8hZelFKV3JDANFhQQiJUAKnDAiUz3x7PltK8cSd4i4eQ3fAe 6CSfXPn/E6syW6ycgFIrlQ2UD8aVZemMWh2992Ie/dIrs0bUG+woMWPpkfSnaq0i9gH7 +NZ/zP1Nh5PBI9v2cPbJ1ABBO8rR44FHPtVax0BSF17wKTmBJ66tTtcyBz7bZ9Rs4dx4 qe7BIfwOKLSqbfai/1YkRArhQPS7faUAzue/a+phMxOBofxGoYH7NTMOzseUi65TdHz7 CcVf3RJwIYUp5aqjWavLed4XOS02r6v1i7p5EaETcMsG8lMcauTpxdAAgT5IZ+4F0QQ3 9m1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:subject:message-id:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to:user-agent; bh=TKETJ59J8B0xhNci58EL1G6g4mmnKZDXYUR/sXhVC4c=; b=JyJP2GfzHAeN/0cbLQGDU2UezUQk694OpBQBal6gu37/bwo9q5aScjZW+/yWCQq8wC vxKeU4KjZb4gptR3N3xMbKZic0YK6guBEbOSCdRYTusKJ0qNcop4Ch1pu1ZZyoAHyRAE tL1U4RJyBWPpu3qYBR47F5tNHdXUwYlfJmWkTjr7aCNIhWFTdCDhU+J1V01jLLsbSAQl Rap3aZo0SHm3XsmEPJwVUvyK/8Td4TIPtaJ45OrBLkhfL3Tph2uhTDBSDQz4Ab0JSfdl u8QLOA2g3/rsskfkH6cPGC71E41+1iIzywFeHQuzvoFIGqkt5Nkvawllzu0T22Ofe5xh A8zg== X-Gm-Message-State: AKaTC010bkpT6t85fyFkqedfk1TA89z7yFLaK1IjdSm3seLDG2iFjwgzKmoBSQH7qrP5zA== X-Received: by 10.28.150.69 with SMTP id y66mr2036596wmd.107.1481625416412; Tue, 13 Dec 2016 02:36:56 -0800 (PST) Date: Tue, 13 Dec 2016 11:36:54 +0100 From: Teubel =?utf-8?Q?Gy=C3=B6rgy?= To: zsh-workers@zsh.org Subject: Re: [PATCH] Bind quasi-default Home, End and Delete keys in built-in keymaps Message-ID: References: <20161212153933.4619-1-tgyurci@gmail.com> <87a8c07h42.fsf@ft.bewatermyfriend.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <87a8c07h42.fsf@ft.bewatermyfriend.org> User-Agent: NeoMutt/20161126 (1.7.1) 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