Skip to content

Commit f40b5b2

Browse files
committed
Simplify history API, now inspired by the readline API
1 parent 5de09dd commit f40b5b2

File tree

8 files changed

+248
-269
lines changed

8 files changed

+248
-269
lines changed

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Async, event-driven and UTF-8 aware standard console input & output (STDIN, STDO
1414
* [Echo](#echo)
1515
* [Input buffer](#input-buffer)
1616
* [Cursor](#cursor)
17+
* [History](#history)
1718
* [Advanced](#advanced)
1819
* [Stdout](#stdout)
1920
* [Stdin](#stdin)
@@ -283,6 +284,57 @@ For example, to move the cursor one character to the left, simply call:
283284
$readline->moveCursorBy(-1);
284285
```
285286

287+
#### History
288+
289+
By default, users can access the history of previous commands by using their
290+
UP and DOWN cursor keys on the keyboard.
291+
The history will start with an empty state, thus this feature is effectively
292+
disabled, as the UP and DOWN cursor keys have no function then.
293+
294+
The `listHistory(): string[]` method can be used to
295+
return an array with all lines in the history.
296+
This will be an empty array until you add new entries via `addHistory()`.
297+
298+
```php
299+
$list = $readline->listHistory();
300+
301+
assert(count($list) === 0);
302+
```
303+
304+
The `addHistory(string $line): Readline` method can be used to
305+
add a new line to the (bottom position of the) history list.
306+
A following `listHistory()` call will return this line as the last element.
307+
308+
```php
309+
$readline->addHistory('a');
310+
$readline->addHistory('b');
311+
312+
$list = $readline->listHistory();
313+
assert($list === array('a', 'b'));
314+
```
315+
316+
The `clearHistory(): Readline` method can be used to
317+
clear the complete history list.
318+
A following `listHistory()` call will return an empty array until you add new
319+
entries via `addHistory()` again.
320+
Note that the history feature will effectively be disabled if the history is
321+
empty, as the UP and DOWN cursor keys have no function then.
322+
323+
```php
324+
$readline->clearHistory();
325+
326+
$list = $readline->listHistory();
327+
assert(count($list) === 0);
328+
```
329+
330+
There is no such thing as a `readHistory()` or `writeHistory()` method
331+
because filesystem operations are inherently blocking and thus beyond the scope
332+
of this library.
333+
Using your favorite filesystem API and an appropriate number of `addHistory()`
334+
or a single `listHistory()` call respectively should be fairly straight
335+
forward and is left up as an exercise for the reader of this documentation
336+
(i.e. *you*).
337+
286338
### Advanced
287339

288340
#### Stdout

src/Readline.php

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
use React\Stream\Util;
99
use Clue\React\Utf8\Sequencer as Utf8Sequencer;
1010
use Clue\React\Term\ControlCodeParser;
11-
use Clue\React\Stdio\Readline\History;
12-
use Clue\React\Stdio\Readline\MemoryHistory;
1311

1412
class Readline extends EventEmitter implements ReadableStreamInterface
1513
{
@@ -19,24 +17,21 @@ class Readline extends EventEmitter implements ReadableStreamInterface
1917
private $echo = true;
2018
private $autocomplete = null;
2119
private $move = true;
22-
private $history;
2320
private $encoding = 'utf-8';
2421

2522
private $input;
2623
private $output;
2724
private $sequencer;
2825
private $closed = false;
2926

30-
public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output, History $history = null)
27+
private $historyLines = array();
28+
private $historyPosition = null;
29+
private $historyUnsaved = null;
30+
31+
public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output)
3132
{
3233
$this->input = $input;
33-
34-
if ($history === null) {
35-
$history = new MemoryHistory();
36-
}
37-
3834
$this->output = $output;
39-
$this->history = $history;
4035

4136
if (!$this->input->isReadable()) {
4237
return $this->close();
@@ -319,32 +314,44 @@ public function getInput()
319314
}
320315

321316
/**
322-
* set history handler to use
317+
* Adds a new line to the (bottom position of the) history list
323318
*
324-
* The history handler will be called whenever the user hits the UP or DOWN
325-
* arrow keys.
326-
*
327-
* If you do not want to use history support, simply pass a `NullHistory` object.
319+
* @param string $line
320+
* @return self
321+
*/
322+
public function addHistory($line)
323+
{
324+
$this->historyLines []= $line;
325+
326+
return $this;
327+
}
328+
329+
/**
330+
* Clears the complete history list
328331
*
329-
* @param History $history new history handler to use
330332
* @return self
331333
*/
332-
public function setHistory(History $history)
334+
public function clearHistory()
333335
{
334-
$this->history = $history;
336+
$this->historyLines = array();
337+
$this->historyPosition = null;
338+
339+
if ($this->historyUnsaved !== null) {
340+
$this->setInput($this->historyUnsaved);
341+
$this->historyUnsaved = null;
342+
}
335343

336344
return $this;
337345
}
338346

339347
/**
340-
* Gets the current history handler in use
348+
* Returns an array with all lines in the history
341349
*
342-
* @return History
343-
* @see self::setHistory()
350+
* @return string[]
344351
*/
345-
public function getHistory()
352+
public function listHistory()
346353
{
347-
return $this->history;
354+
return $this->historyLines;
348355
}
349356

350357
/**
@@ -489,13 +496,40 @@ public function onKeyRight()
489496
/** @internal */
490497
public function onKeyUp()
491498
{
492-
$this->history->moveUp($this);
499+
// ignore if already at top or history is empty
500+
if ($this->historyPosition === 0 || !$this->historyLines) {
501+
return;
502+
}
503+
504+
if ($this->historyPosition === null) {
505+
// first time up => move to last entry
506+
$this->historyPosition = count($this->historyLines) - 1;
507+
$this->historyUnsaved = $this->getInput();
508+
} else {
509+
// somewhere in the list => move by one
510+
$this->historyPosition--;
511+
}
512+
513+
$this->setInput($this->historyLines[$this->historyPosition]);
493514
}
494515

495516
/** @internal */
496517
public function onKeyDown()
497518
{
498-
$this->history->moveDown($this);
519+
// ignore if not currently cycling through history
520+
if ($this->historyPosition === null) {
521+
return;
522+
}
523+
524+
if (($this->historyPosition + 1) < count($this->historyLines)) {
525+
// this is still a valid position => advance by one and apply
526+
$this->historyPosition++;
527+
$this->setInput($this->historyLines[$this->historyPosition]);
528+
} else {
529+
// moved beyond bottom => restore original unsaved input
530+
$this->setInput($this->historyUnsaved);
531+
$this->historyPosition = null;
532+
}
499533
}
500534

501535
/**
@@ -565,7 +599,9 @@ protected function processLine()
565599
}
566600

567601
// process stored input buffer
568-
$this->history->addLine($line);
602+
if ($line !== '') {
603+
$this->addHistory($line);
604+
}
569605
$this->emit('data', array($line));
570606
}
571607

src/Readline/History.php

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/Readline/MemoryHistory.php

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/Readline/NullHistory.php

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)