aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Zegenhagen <[email protected]>2013-07-15 17:03:07 +0200
committerFredrik Gustafsson <[email protected]>2013-08-07 10:05:04 +0200
commit02909c3eaa2b4e636e0f17b24c527879cfc1bdcd (patch)
tree14ecf55bfaf35011b315e4ebcd39c4328d126662
parent3021fca734f71f8bae966ab67f1400d37f8927bc (diff)
downloadotp-02909c3eaa2b4e636e0f17b24c527879cfc1bdcd.tar.gz
otp-02909c3eaa2b4e636e0f17b24c527879cfc1bdcd.tar.bz2
otp-02909c3eaa2b4e636e0f17b24c527879cfc1bdcd.zip
make edlin understand a few important control keys
Hi Fredrik, > I've gotten some feedback from your review, > You need to add documentation under Erts-> "User's Guide" -> "tty - A > command line interface" > > You need to add testcase in interactive_shell_SUITE a simplified > example of how this testcase could look like; > ctrl_w_and_ctrl_u(_Conf) -> > rtnode([{putline,""}, {putline, "2."}, {getline, "2"}, > {putline,"xxx yy"++[$\^w]++"."}, {getline,"xxx"}, {putline,"xxx > yy"++[$\^u]++"z."}, {getline,"z"}],[]). Please find an updated version of the patch attached to this e-mail. I hope that you still accept it via e-mail because the former patch was sent the same way ;-). I have extended the documentation to list the new key combinations and added tests to make sure they work. Kind regards, -- Dr. Stefan Zegenhagen arcutronix GmbH Garbsener Landstr. 10 30419 Hannover Germany Tel: +49 511 277-2734 Fax: +49 511 277-2709 Email: [email protected] Web: www.arcutronix.com *Synchronize the Ethernet* General Managers: Dipl. Ing. Juergen Schroeder, Dr. Josef Gfrerer - Legal Form: GmbH, Registered office: Hannover, HRB 202442, Amtsgericht Hannover; Ust-Id: DE257551767. Please consider the environment before printing this message. >From ce4b827c78d18f39bb1146fd2959ffd7ae2b4bb6 Mon Sep 17 00:00:00 2001 From: Stefan Zegenhagen <[email protected]> Date: Mon, 6 May 2013 14:39:07 +0200 Subject: [PATCH] [EDLIN] support a few more control keys Add support for the following control keys that many users have become accustomed to: - <CTRL>+W : backward kill word - <CTRL>+U : backward kill line - <HOME> : goto start of line - <END> : goto end of line - <CTRL>+<LEFT> : backward word - <CTRL>+<RIGHT> : forward word It seems that the <CTRL>+<LEFT|RIGHT> control key sequences are different between terminal emulators, therefore a few possible combinations were added (similar to how libreadline is configured). Documentation and tests are extended to reflect the new functionality.
-rw-r--r--erts/doc/src/tty.xml26
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl51
-rw-r--r--lib/stdlib/src/edlin.erl30
3 files changed, 103 insertions, 4 deletions
diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index 7d662a2849..15b67c8c7d 100644
--- a/erts/doc/src/tty.xml
+++ b/erts/doc/src/tty.xml
@@ -47,7 +47,7 @@
<section>
<title>Normal Mode</title>
<p>In normal mode keystrokes from the user are collected and interpreted by <c><![CDATA[tty]]></c>. Most of the <em>emacs</em> line editing commands are supported. The following is a complete list of the supported line editing commands.<br></br></p>
- <p><em>Note:</em> The notation <c><![CDATA[C-a]]></c> means pressing the control key and the letter <c><![CDATA[a]]></c> simultaneously. <c><![CDATA[M-f]]></c> means pressing the <c><![CDATA[ESC]]></c> key followed by the letter <c><![CDATA[f]]></c>.
+ <p><em>Note:</em> The notation <c><![CDATA[C-a]]></c> means pressing the control key and the letter <c><![CDATA[a]]></c> simultaneously. <c><![CDATA[M-f]]></c> means pressing the <c><![CDATA[ESC]]></c> key followed by the letter <c><![CDATA[f]]></c>. <c><![CDATA[Home]]></c> and <c><![CDATA[End]]></c> represent the keys with the same name on the keyboard, whereas <c><![CDATA[Left]]></c> and <c><![CDATA[Right]]></c> represent the corresponding cursor keys.
</p>
<table>
<row>
@@ -55,6 +55,10 @@
<cell align="left" valign="middle"><em>Function</em></cell>
</row>
<row>
+ <cell align="left" valign="middle">Home</cell>
+ <cell align="left" valign="middle">Beginning of line</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">C-a</cell>
<cell align="left" valign="middle">Beginning of line</cell>
</row>
@@ -63,6 +67,10 @@
<cell align="left" valign="middle">Backward character</cell>
</row>
<row>
+ <cell align="left" valign="middle">C-Left</cell>
+ <cell align="left" valign="middle">Backward word</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">M-b</cell>
<cell align="left" valign="middle">Backward word</cell>
</row>
@@ -75,6 +83,10 @@
<cell align="left" valign="middle">Delete word</cell>
</row>
<row>
+ <cell align="left" valign="middle">End</cell>
+ <cell align="left" valign="middle">End of line</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">C-e</cell>
<cell align="left" valign="middle">End of line</cell>
</row>
@@ -83,6 +95,10 @@
<cell align="left" valign="middle">Forward character</cell>
</row>
<row>
+ <cell align="left" valign="middle">C-Right</cell>
+ <cell align="left" valign="middle">Forward word</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">M-f</cell>
<cell align="left" valign="middle">Forward word</cell>
</row>
@@ -95,6 +111,10 @@
<cell align="left" valign="middle">Kill line</cell>
</row>
<row>
+ <cell align="left" valign="middle">C-u</cell>
+ <cell align="left" valign="middle">Backward kill line</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">C-l</cell>
<cell align="left" valign="middle">Redraw line</cell>
</row>
@@ -111,6 +131,10 @@
<cell align="left" valign="middle">Transpose characters</cell>
</row>
<row>
+ <cell align="left" valign="middle">C-w</cell>
+ <cell align="left" valign="middle">Backward kill word</cell>
+ </row>
+ <row>
<cell align="left" valign="middle">C-y</cell>
<cell align="left" valign="middle">Insert previously killed text</cell>
</row>
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index d7d9434b1f..a375adceea 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -22,7 +22,7 @@
init_per_group/2,end_per_group/2,
get_columns_and_rows/1, exit_initial/1, job_control_local/1,
job_control_remote/1,
- job_control_remote_noshell/1]).
+ job_control_remote_noshell/1,ctrl_keys/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% For spawn
@@ -41,7 +41,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[get_columns_and_rows, exit_initial, job_control_local,
- job_control_remote, job_control_remote_noshell].
+ job_control_remote, job_control_remote_noshell,
+ ctrl_keys].
groups() ->
[].
@@ -289,7 +290,51 @@ job_control_remote_noshell(Config) when is_list(Config) ->
?line stop_noshell_node(NSNode),
?line Res
end.
-
+
+ctrl_keys(suite) -> [];
+ctrl_keys(doc) -> ["Tests various control keys"];
+ctrl_keys(_Conf) when is_list(_Conf) ->
+ Cu=[$\^u],
+ Cw=[$\^w],
+ Home=[27,$O,$H],
+ End=[27,$O,$F],
+ rtnode([{putline,""},
+ {putline,"2."},
+ {getline,"2"},
+ {putline,"\"hello "++Cw++"world\"."}, % test <CTRL>+W
+ {getline,"\"world\""},
+ {putline,"\"hello "++Cu++"\"world\"."}, % test <CTRL>+U
+ {getline,"\"world\""},
+ {putline,"world\"."++Home++"\"hello "}, % test <HOME>
+ {getline,"\"hello world\""},
+ {putline,"world"++Home++"\"hello "++End++"\"."}, % test <END>
+ {getline,"\"hello world\""}]
+ ++wordLeft()++wordRight(),[]).
+
+
+wordLeft() ->
+ L1=[27,27,$[,$D],
+ L2=[27]++"[5D",
+ L3=[27]++"[1;5D",
+ wordLeft(L1)++wordLeft(L2)++wordLeft(L3).
+
+wordLeft(Chars) ->
+ End=[27,$O,$F],
+ [{putline,"\"world\""++Chars++"hello "++End++"."},
+ {getline,"\"hello world\""}].
+
+wordRight() ->
+ R1=[27,27,$[,$C],
+ R2=[27]++"[5C",
+ R3=[27]++"[1;5C",
+ wordRight(R1)++wordRight(R2)++wordRight(R3).
+
+wordRight(Chars) ->
+ Home=[27,$O,$H],
+ [{putline,"world"++Home++"\"hello "++Chars++"\"."},
+ {getline,"\"hello world\""}].
+
+
rtnode(C,N) ->
rtnode(C,N,[]).
rtnode(Commands,Nodename,ErlPrefix) ->
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 3192879f09..f5998c54fd 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -79,6 +79,14 @@ edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) ->
case key_map(C, Prefix) of
meta ->
edit(Cs, P, {Bef,Aft}, meta, Rs0);
+ meta_o ->
+ edit(Cs, P, {Bef,Aft}, meta_o, Rs0);
+ meta_csi ->
+ edit(Cs, P, {Bef,Aft}, meta_csi, Rs0);
+ meta_meta ->
+ edit(Cs, P, {Bef,Aft}, meta_meta, Rs0);
+ {csi, _} = Csi ->
+ edit(Cs, P, {Bef,Aft}, Csi, Rs0);
meta_left_sq_bracket ->
edit(Cs, P, {Bef,Aft}, meta_left_sq_bracket, Rs0);
search_meta ->
@@ -178,6 +186,7 @@ key_map($\^U, none) -> ctlu;
key_map($\^], none) -> auto_blink;
key_map($\^X, none) -> ctlx;
key_map($\^Y, none) -> yank;
+key_map($\^W, none) -> backward_kill_word;
key_map($\e, none) -> meta;
key_map($), Prefix) when Prefix =/= meta,
Prefix =/= search,
@@ -198,11 +207,29 @@ key_map($d, meta) -> kill_word;
key_map($f, meta) -> forward_word;
key_map($t, meta) -> transpose_word;
key_map($y, meta) -> yank_pop;
+key_map($O, meta) -> meta_o;
+key_map($H, meta_o) -> beginning_of_line;
+key_map($F, meta_o) -> end_of_line;
key_map($\177, none) -> backward_delete_char;
key_map($\177, meta) -> backward_kill_word;
key_map($[, meta) -> meta_left_sq_bracket;
key_map($D, meta_left_sq_bracket) -> backward_char;
key_map($C, meta_left_sq_bracket) -> forward_char;
+% support a few <CTRL>+<CURSOR LEFT|RIGHT> combinations...
+% - forward: \e\e[C, \e[5C, \e[1;5C
+% - backward: \e\e[D, \e[5D, \e[1;5D
+key_map($\e, meta) -> meta_meta;
+key_map($[, meta_meta) -> meta_csi;
+key_map($C, meta_csi) -> forward_word;
+key_map($D, meta_csi) -> backward_word;
+key_map($1, meta_left_sq_bracket) -> {csi, "1"};
+key_map($5, meta_left_sq_bracket) -> {csi, "5"};
+key_map($5, {csi, "1;"}) -> {csi, "1;5"};
+key_map($C, {csi, "5"}) -> forward_word;
+key_map($C, {csi, "1;5"}) -> forward_word;
+key_map($D, {csi, "5"}) -> backward_word;
+key_map($D, {csi, "1;5"}) -> backward_word;
+key_map($;, {csi, "1"}) -> {csi, "1;"};
key_map(C, none) when C >= $\s ->
{insert,C};
%% for search, we need smarter line handling and so
@@ -363,6 +390,9 @@ do_op(end_of_line, Bef, [C|Aft], Rs) ->
{{reverse(Aft, [C|Bef]),[]},[{move_rel,length(Aft)+1}|Rs]};
do_op(end_of_line, Bef, [], Rs) ->
{{Bef,[]},Rs};
+do_op(ctlu, Bef, Aft, Rs) ->
+ put(kill_buffer, Bef),
+ {{[], Aft}, [{delete_chars, -length(Bef)} | Rs]};
do_op(beep, Bef, Aft, Rs) ->
{{Bef,Aft},[beep|Rs]};
do_op(_, Bef, Aft, Rs) ->