33namespace Clue \React \Stdio ;
44
55use Evenement \EventEmitter ;
6+ use React \Stream \ReadableStreamInterface ;
7+ use React \Stream \WritableStreamInterface ;
8+ use React \Stream \Util ;
69
7- class Readline extends EventEmitter
10+ class Readline extends EventEmitter implements ReadableStreamInterface
811{
912 const KEY_BACKSPACE = "\x7f" ;
1013 const KEY_ENTER = "\n" ;
@@ -31,13 +34,20 @@ class Readline extends EventEmitter
3134 private $ history = null ;
3235 private $ encoding = 'utf-8 ' ;
3336
37+ private $ input ;
3438 private $ output ;
3539 private $ sequencer ;
40+ private $ closed = false ;
3641
37- public function __construct ($ output )
42+ public function __construct (ReadableStreamInterface $ input , WritableStreamInterface $ output )
3843 {
44+ $ this ->input = $ input ;
3945 $ this ->output = $ output ;
4046
47+ if (!$ this ->input ->isReadable ()) {
48+ return $ this ->close ();
49+ }
50+
4151 $ this ->sequencer = new Sequencer ();
4252 $ this ->sequencer ->addSequence (self ::KEY_ENTER , array ($ this , 'onKeyEnter ' ));
4353 $ this ->sequencer ->addSequence (self ::KEY_BACKSPACE , array ($ this , 'onKeyBackspace ' ));
@@ -84,6 +94,12 @@ public function __construct($output)
8494 $ this ->sequencer ->addFallback (self ::ESC_SEQUENCE , function ($ bytes ) {
8595 echo 'unknown sequence: ' . ord ($ bytes ) . PHP_EOL ;
8696 });
97+
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 ' ));
87103 }
88104
89105 /**
@@ -369,7 +385,7 @@ public function redraw()
369385 // write output, then move back $reverse chars (by sending backspace)
370386 $ output .= $ buffer . str_repeat ("\x08" , $ this ->strwidth ($ buffer ) - $ this ->getCursorCell ());
371387 }
372- $ this ->write ($ output );
388+ $ this ->output -> write ($ output );
373389
374390 return $ this ;
375391 }
@@ -389,18 +405,12 @@ public function redraw()
389405 public function clear ()
390406 {
391407 if ($ this ->prompt !== '' || ($ this ->echo !== false && $ this ->linebuffer !== '' )) {
392- $ this ->write ("\r\033[K " );
408+ $ this ->output -> write ("\r\033[K " );
393409 }
394410
395411 return $ this ;
396412 }
397413
398- /** @internal */
399- public function onChar ($ char )
400- {
401- $ this ->sequencer ->push ($ char );
402- }
403-
404414 /** @internal */
405415 public function onKeyBackspace ()
406416 {
@@ -449,7 +459,7 @@ public function onKeyTab()
449459 public function onKeyEnter ()
450460 {
451461 if ($ this ->echo !== false ) {
452- $ this ->write ("\n" );
462+ $ this ->output -> write ("\n" );
453463 }
454464 $ this ->processLine ();
455465 }
@@ -571,8 +581,54 @@ private function strwidth($str)
571581 return mb_strwidth ($ str , $ this ->encoding );
572582 }
573583
574- protected function write ($ data )
584+ /** @internal */
585+ public function handleEnd ()
586+ {
587+ if (!$ this ->closed ) {
588+ $ this ->emit ('end ' );
589+ $ this ->close ();
590+ }
591+ }
592+
593+ /** @internal */
594+ public function handleError (\Exception $ error )
595+ {
596+ $ this ->emit ('error ' , array ($ error ));
597+ $ this ->close ();
598+ }
599+
600+ public function isReadable ()
601+ {
602+ return !$ this ->closed && $ this ->input ->isReadable ();
603+ }
604+
605+ public function pause ()
606+ {
607+ $ this ->input ->pause ();
608+ }
609+
610+ public function resume ()
575611 {
576- $ this ->output ->write ($ data );
612+ $ this ->input ->resume ();
613+ }
614+
615+ public function pipe (WritableStreamInterface $ dest , array $ options = array ())
616+ {
617+ Util::pipe ($ this , $ dest , $ options );
618+
619+ return $ dest ;
620+ }
621+
622+ public function close ()
623+ {
624+ if ($ this ->closed ) {
625+ return ;
626+ }
627+
628+ $ this ->closed = true ;
629+
630+ $ this ->input ->close ();
631+
632+ $ this ->emit ('close ' );
577633 }
578634}
0 commit comments