Re: make edlin understand a few important control keys

Stefan Zegenhagen <[email protected]>
Newsgroups gmane.comp.lang.erlang.patches
Organization arcutronix GmbH
Message-ID <1373900587.3597.26.camel@ax-sze>
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.

_______________________________________________
erlang-patches mailing list
[email protected]
http://erlang.org/mailman/listinfo/erlang-patches
edlin.patch (text/x-patch, 9.4 KB)
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.
---
 erts/doc/src/tty.xml                        |   26 +++++++++++++-
 lib/kernel/test/interactive_shell_SUITE.erl |   51 +++++++++++++++++++++++++--
 lib/stdlib/src/edlin.erl                    |   30 ++++++++++++++++
 3 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index 7d662a2..15b67c8 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 d7d9434..a375adc 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 3192879..f5998c5 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) ->
-- 
1.7.9.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.