From 2552ffb4ce7faf17bb0529ce56a7c71cf38acda9 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Fri, 19 Oct 2018 00:18:08 +0300 Subject: [PATCH 01/11] Readline: setSelectTimeout(), setFrameCallback() and various bugfixes related to types --- Source/Readline/Readline.php | 66 ++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index 0f37ab7..5870d80 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -114,7 +114,15 @@ class Readline */ protected $_autocompleter = null; + /** + * @var int + */ + protected $selectTimeout = 30; + /** + * @var callable + */ + protected $frameCallback; /** * Initialize the readline editor. @@ -142,10 +150,28 @@ public function __construct() return; } + + /** + * @param int $timeout + */ + public function setSelectTimeout(int $timeout): void + { + $this->selectTimeout = $timeout; + } + + /** + * @param callable $callback + */ + public function setFrameCallback(callable $callback): void + { + $this->frameCallback = $callback; + + } + /** * Read a line from the input. */ - public function readLine(string $prefix = null): ?string + public function readLine(string $prefix = ''): ?string { $input = Console::getInput(); @@ -180,11 +206,17 @@ public function readLine(string $prefix = null): ?string $output->writeAll($prefix); while (true) { - @stream_select($read, $write, $except, 30, 0); + @stream_select($read, $write, $except, $this->selectTimeout, 0); if (empty($read)) { $read = [$input->getStream()->getStream()]; + if ($this->frameCallback !== null) { + if (call_user_func($this->frameCallback, $this)) { + return null; + } + } + continue; } @@ -192,6 +224,12 @@ public function readLine(string $prefix = null): ?string $this->_buffer = $char; $return = $this->_readLine($char); + if ($this->frameCallback !== null) { + if (call_user_func($this->frameCallback, $this)) { + return null; + } + } + if (0 === ($return & self::STATE_NO_ECHO)) { $output->writeAll($this->_buffer); } @@ -207,7 +245,7 @@ public function readLine(string $prefix = null): ?string /** * Readline core. */ - public function _readLine(string $char): ?string + public function _readLine(string $char) { if (isset($this->_mapping[$char]) && is_callable($this->_mapping[$char])) { @@ -236,9 +274,9 @@ public function _readLine(string $char): ?string $this->getLineCurrent() - 1 ); $this->_buffer = "\033[K" . $tail . str_repeat( - "\033[D", - mb_strlen($tail) - 1 - ); + "\033[D", + mb_strlen($tail) - 1 + ); return static::STATE_CONTINUE; } @@ -366,8 +404,8 @@ public function insertLine(string $insert) } $this->_line = mb_substr($this->_line, 0, $this->_lineCurrent) . - $insert . - mb_substr($this->_line, $this->_lineCurrent); + $insert . + mb_substr($this->_line, $this->_lineCurrent); $this->_lineLength = mb_strlen($this->_line); $this->_lineCurrent += mb_strlen($insert); @@ -440,7 +478,7 @@ public function setAutocompleter(Autocompleter $autocompleter): ?Autocompleter /** * Get the autocompleter. */ - public function getAutocompleter(): Autocompleter + public function getAutocompleter(): ?Autocompleter { return $this->_autocompleter; } @@ -497,7 +535,7 @@ public function _bindArrowUp(self $self): int Console\Cursor::clear('↔'); Console::getOutput()->writeAll($self->getPrefix()); } - $self->setBuffer($buffer = $self->previousHistory()); + $self->setBuffer($buffer = (string) $self->previousHistory()); $self->setLine($buffer); return static::STATE_CONTINUE; @@ -515,7 +553,7 @@ public function _bindArrowDown(self $self): int Console::getOutput()->writeAll($self->getPrefix()); } - $self->setBuffer($buffer = $self->nextHistory()); + $self->setBuffer($buffer = (string) $self->nextHistory()); $self->setLine($buffer); return static::STATE_CONTINUE; @@ -565,7 +603,7 @@ public function _bindArrowLeft(self $self): int */ public function _bindBackspace(self $self): int { - $buffer = null; + $buffer = ''; if (0 < $self->getLineCurrent()) { if (0 === (static::STATE_CONTINUE & static::STATE_NO_ECHO)) { @@ -893,7 +931,7 @@ public function _bindTab(self $self): int }; while (true) { - @stream_select($read, $write, $except, 30, 0); + @stream_select($read, $write, $except, $this->selectTimeout, 0); if (empty($read)) { $read = [$input->getStream()->getStream()]; @@ -983,7 +1021,7 @@ public function _bindTab(self $self): int Console\Cursor::move('←', mb_strlen($tail)); } - // no break + // no break default: $mColumn = -1; $mLine = -1; From e7d18b9129be79ab102b11718ef95ca6aa2b18e4 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Fri, 19 Oct 2018 22:52:59 +0300 Subject: [PATCH 02/11] Readline: proper signal interruption --- Source/Readline/Readline.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index 5870d80..7c93f33 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -206,8 +206,10 @@ public function readLine(string $prefix = ''): ?string $output->writeAll($prefix); while (true) { - @stream_select($read, $write, $except, $this->selectTimeout, 0); - + $select = @stream_select($read, $write, $except, $this->selectTimeout, 0); + if ($select === false) { // if select() is interrupted by signal + $read = []; + } if (empty($read)) { $read = [$input->getStream()->getStream()]; @@ -225,7 +227,7 @@ public function readLine(string $prefix = ''): ?string $return = $this->_readLine($char); if ($this->frameCallback !== null) { - if (call_user_func($this->frameCallback, $this)) { + if ($ret = call_user_func($this->frameCallback, $this)) { return null; } } From 4ee1d8a53005e03699bb6c5ffb800eba5420819d Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Sat, 20 Oct 2018 00:11:32 +0300 Subject: [PATCH 03/11] Fix types --- Source/Readline/Readline.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index 7c93f33..669d5a7 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -575,7 +575,7 @@ public function _bindArrowRight(self $self): int $self->setLineCurrent($self->getLineCurrent() + 1); } - $self->setBuffer(null); + $self->setBuffer(''); return static::STATE_CONTINUE; } @@ -594,7 +594,7 @@ public function _bindArrowLeft(self $self): int $self->setLineCurrent($self->getLineCurrent() - 1); } - $self->setBuffer(null); + $self->setBuffer(''); return static::STATE_CONTINUE; } From 25f426da423186b513cca28df6d3b5ce49eea13a Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Sat, 20 Oct 2018 20:15:33 +0300 Subject: [PATCH 04/11] Cli --- Source/Readline/Readline.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index 669d5a7..1271fa4 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -115,7 +115,7 @@ class Readline protected $_autocompleter = null; /** - * @var int + * @var float */ protected $selectTimeout = 30; @@ -152,9 +152,9 @@ public function __construct() /** - * @param int $timeout + * @param float $timeout */ - public function setSelectTimeout(int $timeout): void + public function setSelectTimeout(float $timeout): void { $this->selectTimeout = $timeout; } @@ -206,7 +206,10 @@ public function readLine(string $prefix = ''): ?string $output->writeAll($prefix); while (true) { - $select = @stream_select($read, $write, $except, $this->selectTimeout, 0); + $select = @stream_select($read, $write, $except, + (int) $this->selectTimeout, + (int) (($this->selectTimeout - (int) $this->selectTimeout) * 1e6) + ); if ($select === false) { // if select() is interrupted by signal $read = []; } @@ -933,7 +936,10 @@ public function _bindTab(self $self): int }; while (true) { - @stream_select($read, $write, $except, $this->selectTimeout, 0); + $select = @stream_select($read, $write, $except, + (int) $this->selectTimeout, + (int) (($this->selectTimeout - (int) $this->selectTimeout) * 1e6) + ); if (empty($read)) { $read = [$input->getStream()->getStream()]; From 94001f33ddba667112a2743e2ca576e54e6191d8 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Mon, 22 Oct 2018 02:16:53 +0300 Subject: [PATCH 05/11] Fix --- Source/Readline/Readline.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index 1271fa4..d8efe30 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -472,7 +472,7 @@ public function getBuffer(): ?string /** * Set an autocompleter. */ - public function setAutocompleter(Autocompleter $autocompleter): ?Autocompleter + public function setAutocompleter(Autocompleter\Autocompleter $autocompleter): ?Autocompleter\Autocompleter { $old = $this->_autocompleter; $this->_autocompleter = $autocompleter; @@ -800,16 +800,18 @@ public function _bindTab(self $self): int ); if (0 === $matches) { - return $state; + $word = ''; + } + else { + $word = $words[0][0]; } - $word = $words[0][0]; - - if ('' === trim($word)) { + /*if ('' === trim($word)) { return $state; - } + }*/ $solution = $autocompleter->complete($word); + $length = mb_strlen($word); if (null === $solution) { @@ -936,7 +938,7 @@ public function _bindTab(self $self): int }; while (true) { - $select = @stream_select($read, $write, $except, + @stream_select($read, $write, $except, (int) $this->selectTimeout, (int) (($this->selectTimeout - (int) $this->selectTimeout) * 1e6) ); From d52a22231dbd1e1eaf83394ca204801e532c8121 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Mon, 29 Oct 2018 17:02:01 +0300 Subject: [PATCH 06/11] More cowbell --- Source/Readline/Readline.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Readline/Readline.php b/Source/Readline/Readline.php index d8efe30..ae5e838 100644 --- a/Source/Readline/Readline.php +++ b/Source/Readline/Readline.php @@ -322,7 +322,7 @@ public function addMapping(string $key, $mapping): void */ public function addHistory(string $line = null) { - if (empty($line)) { + if ($line === null || $line === '') { return; } From ba749a59ee40b72b50181718055719f57f8cd596 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Thu, 10 Jan 2019 02:29:48 +0700 Subject: [PATCH 07/11] Avoiding TypeError --- Source/Cursor.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Cursor.php b/Source/Cursor.php index b44f187..8973fc1 100644 --- a/Source/Cursor.php +++ b/Source/Cursor.php @@ -269,7 +269,7 @@ public static function clear(string $parts = 'all'): void case 'a': case 'all': case '↕': - $output->writeAll($tput->get('clear_screen')); + $output->writeAll($tput->get('clear_screen') ?? ''); static::moveTo(1, 1); break; @@ -284,21 +284,21 @@ public static function clear(string $parts = 'all'): void case 'r': case 'right': case '→': - $output->writeAll($tput->get('clr_eol')); + $output->writeAll($tput->get('clr_eol') ? ''); break; case 'd': case 'down': case '↓': - $output->writeAll($tput->get('clr_eos')); + $output->writeAll($tput->get('clr_eos') ?? ''); break; case 'l': case 'left': case '←': - $output->writeAll($tput->get('clr_bol')); + $output->writeAll($tput->get('clr_bol') ?? ''); break; @@ -317,7 +317,7 @@ public static function clear(string $parts = 'all'): void public static function hide(): void { Console::getOutput()->writeAll( - Console::getTput()->get('cursor_invisible') + Console::getTput()->get('cursor_invisible') ?? '' ); } @@ -327,7 +327,7 @@ public static function hide(): void public static function show(): void { Console::getOutput()->writeAll( - Console::getTput()->get('cursor_visible') + Console::getTput()->get('cursor_visible') ?? '' ); } @@ -685,7 +685,7 @@ public static function setStyle(string $style, bool $blink = true) public static function bip(): void { Console::getOutput()->writeAll( - Console::getTput()->get('bell') + Console::getTput()->get('bell') ?? '' ); } } From b875d4a62ca8b06427d39d4e0e3effc5a76ee04d Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Fri, 11 Jan 2019 13:09:37 +0700 Subject: [PATCH 08/11] Fix --- Source/Cursor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Cursor.php b/Source/Cursor.php index 8973fc1..bf4f084 100644 --- a/Source/Cursor.php +++ b/Source/Cursor.php @@ -284,7 +284,7 @@ public static function clear(string $parts = 'all'): void case 'r': case 'right': case '→': - $output->writeAll($tput->get('clr_eol') ? ''); + $output->writeAll($tput->get('clr_eol') ?? ''); break; From 36319de121fb39964eb569e0303af652043e10fb Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Thu, 5 Aug 2021 01:21:36 +0300 Subject: [PATCH 09/11] Braces --- Source/Chrome/Text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Chrome/Text.php b/Source/Chrome/Text.php index 3fad00b..69aabe5 100644 --- a/Source/Chrome/Text.php +++ b/Source/Chrome/Text.php @@ -360,7 +360,7 @@ public static function underline(string $text, string $pattern = '*'): string foreach ($text as $key => &$value) { $i = -1; $max = strlen($value); - while ($value{++$i} == ' ' && $i < $max); + while ($value[++$i] == ' ' && $i < $max); $underline = str_repeat(' ', $i) . From b90ea9608491c2713fcb6d5b1cd948e04793692e Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Thu, 14 Oct 2021 14:21:58 +0300 Subject: [PATCH 10/11] PHP 8 fix --- Source/Cursor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Cursor.php b/Source/Cursor.php index bf4f084..3b0ad2d 100644 --- a/Source/Cursor.php +++ b/Source/Cursor.php @@ -79,7 +79,7 @@ public static function move(string $steps, int $repeat = 1) $output->writeAll( str_replace( '%p1%d', - $repeat, + (string) $repeat, $tput->get('parm_up_cursor') ) ); From ee89cb3ee02f26495f12716202ed10339e17b517 Mon Sep 17 00:00:00 2001 From: Vasily Zorin Date: Thu, 14 Oct 2021 17:38:55 +0300 Subject: [PATCH 11/11] PHP 8 fix --- Source/Cursor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Cursor.php b/Source/Cursor.php index 3b0ad2d..6cce9fe 100644 --- a/Source/Cursor.php +++ b/Source/Cursor.php @@ -98,7 +98,7 @@ public static function move(string $steps, int $repeat = 1) $output->writeAll( str_replace( '%p1%d', - $repeat, + (string) $repeat, $tput->get('parm_right_cursor') ) ); @@ -117,7 +117,7 @@ public static function move(string $steps, int $repeat = 1) $output->writeAll( str_replace( '%p1%d', - $repeat, + (string) $repeat, $tput->get('parm_down_cursor') ) ); @@ -136,7 +136,7 @@ public static function move(string $steps, int $repeat = 1) $output->writeAll( str_replace( '%p1%d', - $repeat, + (string) $repeat, $tput->get('parm_left_cursor') ) );