-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from jupyterlite/history
Add storage of command history
- Loading branch information
Showing
5 changed files
with
147 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { IOutput } from "./io/output" | ||
|
||
/** | ||
* Command history. Also maintains a current index in the history for scrolling through it. | ||
*/ | ||
export class History { | ||
add(command: string) { | ||
this._current = null | ||
|
||
if (!command.trim()) { | ||
// Do nothing with command that is all whitespace. | ||
return | ||
} | ||
if (this._history.length >= this._maxSize) { | ||
this._history.shift() | ||
} | ||
this._history.push(command) | ||
} | ||
|
||
// Supports negative indexing from end. | ||
at(index: number): string | null { | ||
return this._history.at(index) ?? null | ||
} | ||
|
||
scrollCurrent(next: boolean): string | null { | ||
if (next) { | ||
this._current = (this._current === null) ? null : this._current+1 | ||
} else { | ||
this._current = (this._current === null) ? this._history.length-1 : this._current-1 | ||
} | ||
|
||
if (this._current !== null) { | ||
if (this._current < 0) { | ||
this._current = 0 | ||
} else if (this._current >= this._history.length) { | ||
this._current = null | ||
} | ||
} | ||
|
||
return this._current === null ? null : this.at(this._current) | ||
} | ||
|
||
async write(output: IOutput): Promise<void> { | ||
for (let i = 0; i < this._history.length; i++) { | ||
const index = String(i).padStart(5, ' ') | ||
await output.write(`${index} ${this._history[i]}\n`) | ||
} | ||
} | ||
|
||
private _history: string[] = [] | ||
private _current: number | null = null | ||
|
||
// Smnall number for debug purposes. Should probably get this from an env var. | ||
private _maxSize: number = 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { shell_setup_empty } from "./shell_setup" | ||
|
||
// Not accessing the history object directly, here using the Shell. | ||
|
||
describe("history", () => { | ||
it("should be stored", async () => { | ||
const { shell, output } = await shell_setup_empty() | ||
|
||
await shell._runCommands("cat") | ||
await shell._runCommands("echo") | ||
await shell._runCommands("ls") | ||
output.clear() | ||
|
||
await shell._runCommands("history") | ||
expect(output.text).toEqual(" 0 cat\r\n 1 echo\r\n 2 ls\r\n 3 history\r\n") | ||
}) | ||
|
||
it("should limit storage to max size", async () => { | ||
// TODO: Max size initially hard-coded as 5, will change to use env var. | ||
const { shell, output } = await shell_setup_empty() | ||
|
||
await shell._runCommands("cat") | ||
await shell._runCommands("echo") | ||
await shell._runCommands("ls") | ||
await shell._runCommands("uname") | ||
await shell._runCommands("uniq") | ||
output.clear() | ||
|
||
await shell._runCommands("history") | ||
expect(output.text).toEqual( | ||
" 0 echo\r\n 1 ls\r\n 2 uname\r\n 3 uniq\r\n 4 history\r\n") | ||
}) | ||
|
||
it("should rerun previous command using !index syntax", async () => { | ||
const { shell, output } = await shell_setup_empty() | ||
|
||
await shell._runCommands("cat") | ||
await shell._runCommands("echo hello") | ||
await shell._runCommands("ls") | ||
output.clear() | ||
|
||
await shell._runCommands("!1") | ||
expect(output.text).toEqual("hello\r\n") | ||
}) | ||
|
||
// Need ! out of bounds | ||
|
||
// Need up and down to be tested. | ||
}) |