From bdf2dafe36b2ea2d3b86180424e002967eda9af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Fri, 15 May 2015 01:14:16 +0200 Subject: [PATCH] Support echo replacements (asterisk for password prompts) --- examples/login.php | 2 +- src/Readline.php | 41 ++++++++++++++++++++++++++++++----------- tests/ReadlineTest.php | 21 ++++++++++++++++++++- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/examples/login.php b/examples/login.php index bc2b920..7d6f215 100644 --- a/examples/login.php +++ b/examples/login.php @@ -17,7 +17,7 @@ $stdio->on('line', function ($line) use ($stdio, &$first, &$username, &$password) { if ($first) { $stdio->getReadline()->setPrompt('Password: '); - $stdio->getReadline()->setEcho(false); + $stdio->getReadline()->setEcho('*'); $username = $line; $first = false; } else { diff --git a/src/Readline.php b/src/Readline.php index d9ced50..432f1eb 100644 --- a/src/Readline.php +++ b/src/Readline.php @@ -75,13 +75,28 @@ public function setPrompt($prompt) } /** - * whether or not to echo input + * sets whether/how to echo text input * - * disabling echo output is a good idea for password prompts. Will redraw - * the current prompt and only echo the current input buffer according to - * the new setting. + * The default setting is `true`, which means that every character will be + * echo'ed as-is, i.e. you can see what you're typing. + * For example: Typing "test" shows "test". * - * @param boolean $echo + * You can turn this off by supplying `false`, which means that *nothing* + * will be echo'ed while you're typing. This could be a good idea for + * password prompts. Note that this could be confusing for users, so using + * a character replacement as following is often preferred. + * For example: Typing "test" shows "" (nothing). + * + * Alternative, you can supply a single character replacement character + * that will be echo'ed for each character in the text input. This could + * be a good idea for password prompts, where an asterisk character ("*") + * is often used to indicate typing activity and password length. + * For example: Typing "test" shows "****" (with asterisk replacement) + * + * Changing this setting will redraw the current prompt and echo the current + * input buffer according to the new setting. + * + * @param boolean|string $echo echo can be turned on (boolean true) or off (boolean true), or you can supply a single character replacement string * @return self * @uses self::redraw() */ @@ -91,7 +106,7 @@ public function setEcho($echo) return $this; } - $this->echo = !!$echo; + $this->echo = $echo; // only redraw if there is any input if ($this->linebuffer !== '') { @@ -153,7 +168,7 @@ public function setInput($input) $this->linepos = $this->strlen($this->linebuffer); // only redraw if input should be echo'ed (i.e. is not hidden anyway) - if ($this->echo) { + if ($this->echo !== false) { $this->redraw(); } @@ -219,8 +234,12 @@ public function redraw() { // Erase characters from cursor to end of line $output = "\r\033[K" . $this->prompt; - if ($this->echo) { - $output .= $this->linebuffer; + if ($this->echo !== false) { + if ($this->echo === true) { + $output .= $this->linebuffer; + } else { + $output .= str_repeat($this->echo, $this->strlen($this->linebuffer)); + } $len = $this->strlen($this->linebuffer); if ($this->linepos !== $len) { @@ -237,7 +256,7 @@ public function redraw() public function clear() { - if ($this->prompt !== '' || ($this->echo && $this->linebuffer !== '')) { + if ($this->prompt !== '' || ($this->echo !== false && $this->linebuffer !== '')) { $this->write("\r\033[K"); } // $output = str_repeat("\x09 \x09", strlen($this->prompt . $this->linebuffer)); @@ -275,7 +294,7 @@ public function onKeyTab() public function onKeyEnter() { - if ($this->echo) { + if ($this->echo !== false) { $this->write("\n"); } $this->processLine(); diff --git a/tests/ReadlineTest.php b/tests/ReadlineTest.php index 1600a68..717e5fc 100644 --- a/tests/ReadlineTest.php +++ b/tests/ReadlineTest.php @@ -80,6 +80,16 @@ public function testSettingEchoOnWithInputDoesRedraw() $this->assertSame($this->readline, $this->readline->setEcho(true)); } + public function testSettingEchoAsteriskWithInputDoesRedraw() + { + $this->readline->setPrompt('> '); + $this->readline->setInput('test'); + + $this->output->expects($this->once())->method('write')->with($this->equalTo("\r\033[K" . "> " . "****")); + + $this->assertSame($this->readline, $this->readline->setEcho('*')); + } + public function testSettingEchoOffWithInputDoesRedraw() { $this->readline->setEcho(true); @@ -101,7 +111,16 @@ public function testSettingEchoWithoutInputDoesNotNeedToRedraw() public function testSettingInputDoesRedraw() { - $this->output->expects($this->once())->method('write'); + $this->output->expects($this->once())->method('write')->with($this->equalTo("\r\033[K" . "test")); + $this->assertSame($this->readline, $this->readline->setInput('test')); + } + + public function testSettingInputWithEchoAsteriskDoesRedraw() + { + $this->readline->setEcho('*'); + + $this->output->expects($this->once())->method('write')->with($this->equalTo("\r\033[K" . "****")); + $this->assertSame($this->readline, $this->readline->setInput('test')); }