forked from tools/josh
1
0
Fork 0
josh/src/main/js/InputHistory.ts

115 lines
3.3 KiB
TypeScript

import {IllegalArgumentError} from "./Shared";
/**
* A history of inputs that grows downwards and can be accessed in sequence relative to the newest entry.
*
* An input history keeps a "read index" that starts at `-1`. After entries have been added, calling `previous` will
* increase the read index to `0` and return the newest entry. Calling `previous` again will increase the read index to
* `1` and return the first-to-last entry. Calling `next` at this point will decrease the read index to `0` and will
* return the last entry again. Adding a new entry to the history resets the read index to `-1`. Calling `next` while
* the read index is at `-1` will return an empty string without decrementing the read index further. Calling `previous`
* at the highest possible index will return the first entry without incrementing the read index further.
*/
export class InputHistory {
/**
* The list of previous input.
*/
private readonly _entries: string[];
/**
* The current index that the history is being read from.
*/
private index: number;
/**
* Constructs a new input history.
*
* @param history the records currently in the history
*/
constructor(history: string[] = []) {
this._entries = history;
this.index = -1;
}
/**
* Returns a copy of the entries in this history.
*/
get entries(): string[] {
return this._entries.slice();
}
/**
* Adds a new input to the bottom of the history and resets the read index.
*
* @param entry the entry to add
*/
add(entry: string): void {
if (entry.trim() !== "" && entry.trim() !== this._entries[0]?.trim())
this._entries.unshift(entry);
this.resetIndex();
}
/**
* Removes all entries from the history and resets the read index.
*/
clear(): void {
this._entries.length = 0;
this.resetIndex();
}
/**
* Returns the entry at the given index, or an empty string if the index is negative.
*
* @param index the index to return the entry of, where `0` is the newest entry and `-1` returns an empty string
* @throws if the index is out of bounds and not `-1`
*/
get(index: number): string {
if (index < -1 || index >= this._entries.length)
throw new IllegalArgumentError(`Index '${index}' is out of bounds.`);
if (index === -1)
return "";
return this._entries[index];
}
/**
* Returns the next (newer) entry in the history, or an empty string if the read index has gone past the newest
* entry.
*
* The read counter is decremented if possible.
*/
next(): string {
this.index--;
if (this.index < -1)
this.index = -1;
return this.get(this.index);
}
/**
* Returns the previous (older) entry in the history, or the oldest entry if the read index is already at the oldest
* entry.
*
* The read counter is incremented if possible.
*/
previous(): string {
this.index++;
if (this.index >= this._entries.length)
this.index = this._entries.length - 1;
return this.get(this.index);
}
/**
* Resets the read index without changing any entries.
*/
resetIndex(): void {
this.index = -1;
}
}