Files
llama.cpp/tools/ui/src/lib/utils/source-history.ts
T
Aleksander Grygier fc6545d322 allozaur/feat/chat form contenteditable (#26717)
* feat: Add contenteditable tokenizer for badge/code-chip chat input

* feat: Add source-space undo/redo history for the rich input

* feat: Split text glued to a closing code fence onto its own line

* feat: Add ChatFormContenteditable rich input renderer

* feat : wire the contenteditable into ChatForm with auto-switch gating
2026-08-07 20:40:10 +02:00

49 lines
1.4 KiB
TypeScript

/**
* Source-space undo/redo history for the chat-form contenteditable, whose
* imperative DOM rebuilds destroy the browser's native undo stack.
* Entries record the state BEFORE an edit; edits within `groupWindowMs`
* extend the open group so a typing burst undoes as a unit, while
* structural edits (paste, mention insert, clear) pass `newGroup`.
*/
export interface SourceHistoryEntry {
value: string;
caret: number;
}
export class SourceHistory {
private undoStack: SourceHistoryEntry[] = [];
private redoStack: SourceHistoryEntry[] = [];
private lastPush = 0;
constructor(
private limit = 100,
private groupWindowMs = 800
) {}
push(entry: SourceHistoryEntry, now: number, newGroup = false): void {
if (newGroup || now - this.lastPush >= this.groupWindowMs || this.undoStack.length === 0) {
this.undoStack.push(entry);
if (this.undoStack.length > this.limit) this.undoStack.shift();
}
this.lastPush = now;
this.redoStack = [];
}
undo(current: SourceHistoryEntry): SourceHistoryEntry | null {
const entry = this.undoStack.pop();
if (!entry) return null;
this.redoStack.push(current);
this.lastPush = 0; // the next edit after an undo starts a new group
return entry;
}
redo(current: SourceHistoryEntry): SourceHistoryEntry | null {
const entry = this.redoStack.pop();
if (!entry) return null;
this.undoStack.push(current);
this.lastPush = 0;
return entry;
}
}