66use React \Stream \ReadableStreamInterface ;
77use React \Stream \WritableStreamInterface ;
88use React \Stream \Util ;
9+ use Clue \React \Utf8 \Sequencer as Utf8Sequencer ;
10+ use Clue \React \Term \ControlCodeParser ;
911
1012class Readline extends EventEmitter implements ReadableStreamInterface
1113{
12- const KEY_BACKSPACE = "\x7f" ;
13- const KEY_ENTER = "\n" ;
14- const KEY_TAB = "\t" ;
15-
16- const ESC_SEQUENCE = "\033[ " ;
17- const ESC_LEFT = "D " ;
18- const ESC_RIGHT = "C " ;
19- const ESC_UP = "A " ;
20- const ESC_DOWN = "B " ;
21- const ESC_HOME = "1~ " ;
22- const ESC_INS = "2~ " ;
23- const ESC_DEL = "3~ " ;
24- const ESC_END = "4~ " ;
25-
26- const ESC_F10 = "20~ " ;
27-
2814 private $ prompt = '' ;
2915 private $ linebuffer = '' ;
3016 private $ linepos = 0 ;
@@ -48,58 +34,46 @@ public function __construct(ReadableStreamInterface $input, WritableStreamInterf
4834 return $ this ->close ();
4935 }
5036
51- $ this ->sequencer = new Sequencer ();
52- $ this ->sequencer ->addSequence (self ::KEY_ENTER , array ($ this , 'onKeyEnter ' ));
53- $ this ->sequencer ->addSequence (self ::KEY_BACKSPACE , array ($ this , 'onKeyBackspace ' ));
54- $ this ->sequencer ->addSequence (self ::KEY_TAB , array ($ this , 'onKeyTab ' ));
55-
56- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_LEFT , array ($ this , 'onKeyLeft ' ));
57- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_RIGHT , array ($ this , 'onKeyRight ' ));
58- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_UP , array ($ this , 'onKeyUp ' ));
59- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_DOWN , array ($ this , 'onKeyDown ' ));
60- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_HOME , array ($ this , 'onKeyHome ' ));
61- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_INS , array ($ this , 'onKeyInsert ' ));
62- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_DEL , array ($ this , 'onKeyDelete ' ));
63- $ this ->sequencer ->addSequence (self ::ESC_SEQUENCE . self ::ESC_END , array ($ this , 'onKeyEnd ' ));
64-
65- $ expect = 0 ;
66- $ char = '' ;
37+ // push input through control code parser
38+ $ parser = new ControlCodeParser ($ input );
39+
6740 $ that = $ this ;
68- $ this ->sequencer ->addFallback ('' , function ($ byte ) use (&$ expect , &$ char , $ that ) {
69- if ($ expect === 0 ) {
70- $ code = ord ($ byte );
71- // count number of bytes expected for this UTF-8 multi-byte character
72- $ expect = 1 ;
73- if ($ code & 128 && $ code & 64 ) {
74- ++$ expect ;
75- if ($ code & 32 ) {
76- ++$ expect ;
77- if ($ code & 16 ) {
78- ++$ expect ;
79- }
80- }
81- }
41+ $ codes = array (
42+ "\n" => 'onKeyEnter ' ,
43+ "\x7f" => 'onKeyBackspace ' ,
44+ "\t" => 'onKeyTab ' ,
45+
46+ "\033[A " => 'onKeyUp ' ,
47+ "\033[B " => 'onKeyDown ' ,
48+ "\033[C " => 'onKeyRight ' ,
49+ "\033[D " => 'onKeyLeft ' ,
50+
51+ "\033[1~ " => 'onKeyHome ' ,
52+ "\033[2~ " => 'onKeyInsert ' ,
53+ "\033[3~ " => 'onKeyDelete ' ,
54+ "\033[4~ " => 'onKeyEnd ' ,
55+
56+ // "\033[20~" => 'onKeyF10',
57+ );
58+ $ decode = function ($ code ) use ($ codes , $ that ) {
59+ if (isset ($ codes [$ code ])) {
60+ $ method = $ codes [$ code ];
61+ $ that ->$ method ($ code );
62+ return ;
8263 }
83- $ char .= $ byte ;
84- --$ expect ;
85-
86- // forward buffered bytes as a single multi byte character once last byte has been read
87- if ($ expect === 0 ) {
88- $ save = $ char ;
89- $ char = '' ;
90- $ that ->onFallback ($ save );
91- }
92- });
64+ };
65+
66+ $ parser ->on ('csi ' , $ decode );
67+ $ parser ->on ('c0 ' , $ decode );
9368
94- $ this -> sequencer -> addFallback ( self :: ESC_SEQUENCE , function ( $ bytes ) {
95- echo ' unknown sequence: ' . ord ( $ bytes ) . PHP_EOL ;
96- } );
69+ // push resulting data through utf8 sequencer
70+ $ utf8 = new Utf8Sequencer ( $ parser ) ;
71+ $ utf8 -> on ( ' data ' , array ( $ this , ' onFallback ' ) );
9772
98- // input data emits a single char into readline
99- $ input ->on ('data ' , array ($ this ->sequencer , 'push ' ));
100- $ input ->on ('end ' , array ($ this , 'handleEnd ' ));
101- $ input ->on ('error ' , array ($ this , 'handleError ' ));
102- $ input ->on ('close ' , array ($ this , 'close ' ));
73+ // process all stream events (forwarded from input stream)
74+ $ utf8 ->on ('end ' , array ($ this , 'handleEnd ' ));
75+ $ utf8 ->on ('error ' , array ($ this , 'handleError ' ));
76+ $ utf8 ->on ('close ' , array ($ this , 'close ' ));
10377 }
10478
10579 /**
@@ -519,7 +493,7 @@ public function onFallback($chars)
519493 $ post = $ this ->substr ($ this ->linebuffer , $ this ->linepos );
520494
521495 $ this ->linebuffer = $ pre . $ chars . $ post ;
522- ++ $ this ->linepos ;
496+ $ this ->linepos += $ this -> strlen ( $ chars ) ;
523497
524498 $ this ->redraw ();
525499 }
0 commit comments