Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions src/Readline.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ public function __construct($output)
*/
public function setPrompt($prompt)
{
if ($prompt === $this->prompt) {
return $this;
}

$this->prompt = $prompt;
$this->redraw();

return $this;
return $this->redraw();
}

/**
Expand All @@ -84,8 +87,16 @@ public function setPrompt($prompt)
*/
public function setEcho($echo)
{
if ($echo === $this->echo) {
return $this;
}

$this->echo = !!$echo;
$this->redraw();

// only redraw if there is any input
if ($this->linebuffer !== '') {
$this->redraw();
}

return $this;
}
Expand All @@ -104,10 +115,7 @@ public function setMove($move)
{
$this->move = !!$move;

$this->linepos = $this->strlen($this->linebuffer);
$this->redraw();

return $this;
return $this->moveCursorTo($this->strlen($this->linebuffer));
}

/**
Expand Down Expand Up @@ -137,9 +145,17 @@ public function getCursorPosition()
*/
public function setInput($input)
{
if ($this->linebuffer === $input) {
return $this;
}

$this->linebuffer = $input;
$this->linepos = $this->strlen($this->linebuffer);
$this->redraw();

// only redraw if input should be echo'ed (i.e. is not hidden anyway)
if ($this->echo) {
$this->redraw();
}

return $this;
}
Expand Down Expand Up @@ -189,9 +205,15 @@ public function setAutocomplete(AutocompleteInterface $autocomplete = null)
/**
* redraw the current input prompt
*
* Usually, there should be no need to to call this method manually. It will
* be invoked automatically whenever we detect the readline input needs to
* be (re)written to the output.
*
* Clear the current line and draw the input prompt. If input echo is
* enabled, will also draw the current input buffer and move to the current
* input buffer position.
*
* @return self
*/
public function redraw()
{
Expand All @@ -209,6 +231,8 @@ public function redraw()
}
}
$this->write($output);

return $this;
}

public function clear()
Expand Down Expand Up @@ -358,11 +382,15 @@ public function moveCursorBy($n)
public function moveCursorTo($n)
{
if ($n < 0 || $n === $this->linepos || $n > $this->strlen($this->linebuffer)) {
return;
return $this;
}

$this->linepos = $n;
$this->redraw();

// only redraw if cursor is actually visible
if ($this->echo) {
$this->redraw();
}

return $this;
}
Expand Down
83 changes: 81 additions & 2 deletions tests/ReadlineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class ReadlineTest extends TestCase
{
public function setUp()
{
$output = $this->getMockBuilder('Clue\React\Stdio\Stdout')->disableOriginalConstructor()->getMock();
$this->readline = new Readline($output);
$this->output = $this->getMockBuilder('Clue\React\Stdio\Stdout')->disableOriginalConstructor()->getMock();
$this->readline = new Readline($this->output);
}

public function testSettersReturnSelf()
Expand Down Expand Up @@ -45,4 +45,83 @@ public function testMultiByteInput()
$this->assertEquals('täst', $this->readline->getInput());
$this->assertEquals(4, $this->readline->getCursorPosition());
}

public function testRedrawingReadlineWritesToOutputOnce()
{
$this->readline->setPrompt('> ');
$this->readline->setInput('test');
$this->readline->moveCursorBy(-2);

$this->output->expects($this->once())->method('write')->with($this->equalTo("\r\033[K" . "> " . "test" . "\x08\x08"));
$this->assertSame($this->readline, $this->readline->redraw());
}

public function testSettingSameSettingsDoesNotNeedToRedraw()
{
$this->readline->setPrompt('> ');
$this->readline->setInput('test');
$this->readline->moveCursorBy(-2);

$this->output->expects($this->never())->method('write');

$this->assertSame($this->readline, $this->readline->setPrompt('> '));
$this->assertSame($this->readline, $this->readline->setInput('test'));
$this->assertSame($this->readline, $this->readline->moveCursorTo(2));
}

public function testSettingEchoOnWithInputDoesRedraw()
{
$this->readline->setEcho(false);
$this->readline->setPrompt('> ');
$this->readline->setInput('test');

$this->output->expects($this->once())->method('write')->with($this->equalTo("\r\033[K" . "> " . "test"));

$this->assertSame($this->readline, $this->readline->setEcho(true));
}

public function testSettingEchoOffWithInputDoesRedraw()
{
$this->readline->setEcho(true);
$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(false));
}

public function testSettingEchoWithoutInputDoesNotNeedToRedraw()
{
$this->output->expects($this->never())->method('write');

$this->assertSame($this->readline, $this->readline->setEcho(false));
$this->assertSame($this->readline, $this->readline->setEcho(true));
}

public function testSettingInputDoesRedraw()
{
$this->output->expects($this->once())->method('write');
$this->assertSame($this->readline, $this->readline->setInput('test'));
}

public function testSettingInputWithoutEchoDoesNotNeedToRedraw()
{
$this->readline->setEcho(false);

$this->output->expects($this->never())->method('write');

$this->assertSame($this->readline, $this->readline->setInput('test'));
}

public function testMovingCursorWithoutEchoDoesNotNeedToRedraw()
{
$this->readline->setEcho(false);
$this->readline->setInput('test');

$this->output->expects($this->never())->method('write');

$this->assertSame($this->readline, $this->readline->moveCursorTo(0));
$this->assertSame($this->readline, $this->readline->moveCursorBy(2));
}
}