Skip to content

Commit 6664dcd

Browse files
committed
Limit history to 500 lines by default and add limitHistory() method
1 parent 0c2b183 commit 6664dcd

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,29 @@ $list = $readline->listHistory();
346346
assert(count($list) === 0);
347347
```
348348

349+
The `limitHistory(?int $limit): Readline` method can be used to
350+
set a limit of history lines to keep in memory.
351+
By default, only the last 500 lines will be kept in memory and everything else
352+
will be discarded.
353+
You can use an integer value to limit this to the given number of entries or
354+
use `null` for an unlimited number (not recommended, because everything is
355+
kept in RAM).
356+
If you set the limit to `0` (int zero), the history will effectively be
357+
disabled, as no lines can be added to or returned from the history list.
358+
If you're building a CLI application, you may also want to use something like
359+
this to obey the `HISTSIZE` environment variable:
360+
361+
```php
362+
$limit = getenv('HISTSIZE');
363+
if ($limit === '' || $limit < 0) {
364+
// empty string or negative value means unlimited
365+
$readline->limitHistory(null);
366+
} elseif ($limit !== false) {
367+
// apply any other value if given
368+
$readline->limitHistory($limit);
369+
}
370+
```
371+
349372
There is no such thing as a `readHistory()` or `writeHistory()` method
350373
because filesystem operations are inherently blocking and thus beyond the scope
351374
of this library.

examples/periodic.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111

1212
$readline->setPrompt('> ');
1313

14+
// limit history to HISTSIZE env
15+
$limit = getenv('HISTSIZE');
16+
if ($limit === '' || $limit < 0) {
17+
// empty string or negative value means unlimited
18+
$readline->limitHistory(null);
19+
} elseif ($limit !== false) {
20+
// apply any other value if given
21+
$readline->limitHistory($limit);
22+
}
23+
1424
// add all lines from input to history
1525
$readline->on('data', function ($line) use ($readline) {
1626
$all = $readline->listHistory();

src/Readline.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Readline extends EventEmitter implements ReadableStreamInterface
2727
private $historyLines = array();
2828
private $historyPosition = null;
2929
private $historyUnsaved = null;
30+
private $historyLimit = 500;
3031

3132
public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output)
3233
{
@@ -323,6 +324,10 @@ public function addHistory($line)
323324
{
324325
$this->historyLines []= $line;
325326

327+
if ($this->historyLimit !== null) {
328+
$this->historyLines = array_slice($this->historyLines, -$this->historyLimit, $this->historyLimit);
329+
}
330+
326331
return $this;
327332
}
328333

@@ -354,6 +359,23 @@ public function listHistory()
354359
return $this->historyLines;
355360
}
356361

362+
/**
363+
* Limits the history to a maximum of N entries and truncates the current history list accordingly
364+
*
365+
* @param int|null $limit
366+
* @return self
367+
*/
368+
public function limitHistory($limit)
369+
{
370+
$this->historyLimit = $limit === null ? null : (int)$limit;
371+
372+
if ($this->historyLimit !== null) {
373+
$this->historyLines = array_slice($this->historyLines, -$this->historyLimit, $this->historyLimit);
374+
}
375+
376+
return $this;
377+
}
378+
357379
/**
358380
* set autocompletion handler to use (or none)
359381
*

tests/ReadlineTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,4 +777,66 @@ public function testHistoryClearWhileCyclingRestoresOriginalInput()
777777

778778
$this->assertEquals('hello', $this->readline->getInput());
779779
}
780+
781+
public function testHistoryLimitReturnsSelf()
782+
{
783+
$this->assertSame($this->readline, $this->readline->limitHistory(100));
784+
}
785+
786+
public function testHistoryLimitTruncatesCurrentListToLimit()
787+
{
788+
$this->readline->addHistory('a');
789+
$this->readline->addHistory('b');
790+
$this->readline->addHistory('c');
791+
792+
$this->readline->limitHistory(2);
793+
794+
$this->assertCount(2, $this->readline->listHistory());
795+
$this->assertEquals(array('b', 'c'), $this->readline->listHistory());
796+
}
797+
798+
public function testHistoryLimitToZeroEmptiesCurrentList()
799+
{
800+
$this->readline->addHistory('a');
801+
$this->readline->addHistory('b');
802+
$this->readline->addHistory('c');
803+
804+
$this->readline->limitHistory(0);
805+
806+
$this->assertCount(0, $this->readline->listHistory());
807+
}
808+
809+
public function testHistoryLimitTruncatesAddingBeyondLimit()
810+
{
811+
$this->readline->limitHistory(2);
812+
813+
$this->readline->addHistory('a');
814+
$this->readline->addHistory('b');
815+
$this->readline->addHistory('c');
816+
817+
$this->assertCount(2, $this->readline->listHistory());
818+
$this->assertEquals(array('b', 'c'), $this->readline->listHistory());
819+
}
820+
821+
public function testHistoryLimitZeroAlwaysReturnsEmpty()
822+
{
823+
$this->readline->limitHistory(0);
824+
825+
$this->readline->addHistory('a');
826+
$this->readline->addHistory('b');
827+
$this->readline->addHistory('c');
828+
829+
$this->assertCount(0, $this->readline->listHistory());
830+
}
831+
832+
public function testHistoryLimitUnlimitedDoesNotTruncate()
833+
{
834+
$this->readline->limitHistory(null);
835+
836+
for ($i = 0; $i < 1000; ++$i) {
837+
$this->readline->addHistory('line' . $i);
838+
}
839+
840+
$this->assertCount(1000, $this->readline->listHistory());
841+
}
780842
}

0 commit comments

Comments
 (0)