bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Patch to make readline parse CSI keycodes properly


From: Andy Koppe
Subject: Patch to make readline parse CSI keycodes properly
Date: Sun, 19 Jul 2009 11:04:09 -0700 (PDT)
User-agent: G2/1.0

Hi,

This is about a small problem with readline that has long been bugging
me: when pressing an unbound key or key combination in bash and other
readline programs, somewhat cryptic characters are often inserted into
the command line. For example, you might get "~" for Insert, "4~" for
F12, or ";5A" for Ctrl+Up. This can be particularly confusing for new
users.

The reason for this issue is that readline does not parse control
sequences as defined in section 5.4 of the ECMA-48 standard correctly.
VT100 terminals and its numerous descendants of course use those for
many keys or key combinations that don't have single-character codes.
They start with the control sequence introducer (CSI), normally
represented by "\e[", followed by parameter and intermediate bytes in
the range from 0x20 to 0x3F, followed by a final byte in the range
from 0x40 to 0x7E. Readline, at least in its default config, stops
parsing these sequences after the first byte following the "\e[",
leaving any remaining bytes to spill onto the command line.

As far as I understand it, there's currently no way to address this in
the readline config, short of
explicitly binding all the CSI keycodes to nothing anyway. Well
actually, a single binding seems to suffice for codes that differ only
in the last character, but that doesn't help with the F-keys and the
likes of Insert. Either way, it would be a rather long list of
bindings, which would slow down startup and lead to an explosion in
the number of keymaps allocated internally by readline.

Hence the small patch below, which avoids such inefficiencies. It
defines a function called 'skip-csi-seq' that skips over the
parameter, intermediate, and final bytes. This is assigned to "\e[".
Since bindings for longer sequences take precedence over shorter ones,
CSI sequences that do have functions bound to them continue to work.

Here's the result in the output of 'bind':

$ bind -p | grep e\\[
"\e[D": backward-char
"\e[H": beginning-of-line
"\e[3~": delete-char
"\e[F": end-of-line
"\e[C": forward-char
"\e[B": next-history
"\e[A": previous-history
"\e[": skip-csi-seq

This is working correctly here, including when adding bindings for
longer keycodes: no more odd characters being inserted when
accidentally hitting the wrong key. Please consider this for inclusion
into readline.

Kind regards,
Andy


--- emacs_keymap.c      2009-01-04 19:32:32.000000000 +0000
+++ emacs_keymap.c      2009-07-19 08:23:32.796875000 +0100
@@ -417,7 +417,7 @@
   { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */

   /* Some more punctuation. */
-  { ISFUNC, (rl_command_func_t *)0x0 },                /* Meta-[ */    /* was
rl_arrow_keys */
+  { ISFUNC, rl_skip_csi_seq },                 /* Meta-[ */    /* was 
rl_arrow_keys */
   { ISFUNC, rl_delete_horizontal_space },      /* Meta-\ */
   { ISFUNC, (rl_command_func_t *)0x0 },                /* Meta-] */
   { ISFUNC, (rl_command_func_t *)0x0 },                /* Meta-^ */
--- funmap.c    2009-01-04 19:32:33.000000000 +0000
+++ funmap.c    2009-07-19 08:25:34.906250000 +0100
@@ -123,6 +123,7 @@
   { "revert-line", rl_revert_line },
   { "self-insert", rl_insert },
   { "set-mark", rl_set_mark },
+  { "skip-csi-seq", rl_skip_csi_seq },
   { "start-kbd-macro", rl_start_kbd_macro },
   { "tab-insert", rl_tab_insert },
   { "tilde-expand", rl_tilde_expand },
--- readline.h  2009-07-19 05:28:30.000000000 +0100
+++ readline.h  2009-07-19 08:23:38.546875000 +0100
@@ -197,6 +197,7 @@
 /* Miscellaneous bindable commands. */
 extern int rl_abort PARAMS((int, int));
 extern int rl_tty_status PARAMS((int, int));
+extern int rl_skip_csi_seq PARAMS((int, int));

 /* Bindable commands for incremental and non-incremental history
searching. */
 extern int rl_history_search_forward PARAMS((int, int));
--- text.c      2009-01-04 19:32:34.000000000 +0000
+++ text.c      2009-07-19 08:23:45.890625000 +0100
@@ -571,6 +571,18 @@
 }

 int
+rl_skip_csi_seq (count, c)
+     int count, c;
+{
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  do
+    c = rl_read_key ();
+  while (c >= 0x20 && c < 0x40);
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+  return 0;
+}
+
+int
 rl_arrow_keys (count, c)
      int count, c;
 {


reply via email to

[Prev in Thread] Current Thread [Next in Thread]