mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-26 13:27:05 +08:00
133 lines
3.1 KiB
JavaScript
133 lines
3.1 KiB
JavaScript
/**
|
|
* Allows for recording a sequence of focused cells with the focused line
|
|
* and navigate inside this stack.
|
|
*/
|
|
export default class CursorHistory {
|
|
/** @private */
|
|
entries = [];
|
|
|
|
/** @private */
|
|
index = -1;
|
|
|
|
/**
|
|
* Adds a new cell to the stack.
|
|
*
|
|
* If the stack length is greater than the stack limit,
|
|
* it will remove the oldest entries.
|
|
*/
|
|
push(cellId, line, offset) {
|
|
const entry = { cellId, line, offset };
|
|
|
|
if (this.isSameCell(cellId)) {
|
|
this.entries[this.index] = entry;
|
|
} else {
|
|
if (this.entries[this.index + 1] !== undefined) {
|
|
this.entries = this.entries.slice(0, this.index + 1);
|
|
}
|
|
|
|
this.entries.push(entry);
|
|
this.index++;
|
|
}
|
|
|
|
if (this.entries.length > 20) {
|
|
this.entries.shift();
|
|
this.index--;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all matching cells with given id from the stack.
|
|
*/
|
|
removeAllFromCell(cellId) {
|
|
// We need to make sure the last entry from history
|
|
// doesn't belong to the given cell id that we need
|
|
// to remove from the entries list.
|
|
let cellIdCount = 0;
|
|
|
|
for (let i = 0; i <= this.index; i++) {
|
|
const entry = this.get(i);
|
|
if (entry.cellId === cellId) cellIdCount++;
|
|
}
|
|
|
|
this.entries = this.entries.filter((entry) => entry.cellId !== cellId);
|
|
this.index = this.index - cellIdCount;
|
|
if (this.index === -1 && this.entries.length > 0) this.index = 0;
|
|
}
|
|
|
|
/**
|
|
* Checks if the current stack is available to navigate back.
|
|
*/
|
|
canGoBack() {
|
|
return this.canGetFromHistory(-1);
|
|
}
|
|
|
|
/**
|
|
* Navigates back in the current stack.
|
|
*
|
|
* If the navigation succeeds, it will return the entry from current index.
|
|
* Otherwise, returns null;
|
|
*/
|
|
goBack() {
|
|
return this.getFromHistory(-1);
|
|
}
|
|
|
|
/**
|
|
* Checks if the current stack is available to navigate forward.
|
|
*/
|
|
canGoForward() {
|
|
return this.canGetFromHistory(1);
|
|
}
|
|
|
|
/**
|
|
* Navigates forward in the current stack.
|
|
*
|
|
* If the navigation succeeds, it will return the entry from current index.
|
|
* Otherwise, returns null;
|
|
*/
|
|
goForward() {
|
|
return this.getFromHistory(1);
|
|
}
|
|
|
|
/**
|
|
* Gets the entry in the current stack.
|
|
*
|
|
* If the stack have at least one entry, it will return the entry from current index.
|
|
* Otherwise, returns null;
|
|
*/
|
|
getCurrent() {
|
|
return this.get(this.index);
|
|
}
|
|
|
|
/** @private **/
|
|
getEntries() {
|
|
return this.entries;
|
|
}
|
|
|
|
/** @private **/
|
|
get(index) {
|
|
if (this.entries.length <= 0) return null;
|
|
return this.entries[index];
|
|
}
|
|
|
|
/** @private **/
|
|
getFromHistory(direction) {
|
|
if (!this.canGetFromHistory(direction)) return null;
|
|
|
|
this.index = Math.max(0, this.index + direction);
|
|
return this.entries[this.index];
|
|
}
|
|
|
|
/** @private **/
|
|
canGetFromHistory(direction) {
|
|
if (this.entries.length === 0) return false;
|
|
|
|
const index = this.index + direction;
|
|
return 0 <= index && index < this.entries.length;
|
|
}
|
|
|
|
/** @private **/
|
|
isSameCell(cellId) {
|
|
const lastEntry = this.get(this.index);
|
|
return lastEntry !== null && cellId === lastEntry.cellId;
|
|
}
|
|
}
|