send some information about text effects to onevent so we can do better cursor tracking
This commit is contained in:
parent
916a5b46f3
commit
2263b23634
2 changed files with 40 additions and 12 deletions
|
@ -8,9 +8,16 @@ const textarea = document.querySelector("textarea")!;
|
|||
const pt = new PlainTextORDT();
|
||||
let me: string | undefined = undefined;
|
||||
|
||||
pt.onevent = event => {
|
||||
pt.onevent = (event, textIndex, affectedLength) => {
|
||||
if (event.at[0] === me) return;
|
||||
|
||||
let start = textarea.selectionStart,
|
||||
end = textarea.selectionEnd;
|
||||
if (textIndex <= start) start += affectedLength;
|
||||
if (textIndex <= end) end += affectedLength;
|
||||
|
||||
textarea.value = pt.render()[0];
|
||||
textarea.setSelectionRange(start, end);
|
||||
};
|
||||
|
||||
const socket = new WebSocket("/api/connect");
|
||||
|
|
|
@ -9,7 +9,11 @@ export type PlainTextOperation =
|
|||
| { type: "delete" };
|
||||
|
||||
export class PlainTextORDT extends CausalTree<PlainTextOperation> {
|
||||
onevent?: (op: CausalTreeOp<PlainTextOperation>) => void;
|
||||
onevent?: (
|
||||
op: CausalTreeOp<PlainTextOperation>,
|
||||
textIndex: number,
|
||||
affectedLength: number,
|
||||
) => void;
|
||||
|
||||
// caches for insert op <=> text transformation,
|
||||
// all these arrays should be the same length (SoA)
|
||||
|
@ -21,12 +25,13 @@ export class PlainTextORDT extends CausalTree<PlainTextOperation> {
|
|||
override apply(op: AnyCausalTreeOp<PlainTextOperation>): number {
|
||||
const opIdx = super.apply(op);
|
||||
op = this.operations[opIdx];
|
||||
this.#applyCacheUpdate(op, opIdx);
|
||||
this.onevent?.(op);
|
||||
|
||||
const [idx, len] = this.#applyCacheUpdate(op, opIdx);
|
||||
this.onevent?.(op, idx, len);
|
||||
return opIdx;
|
||||
}
|
||||
|
||||
#applyCacheUpdate(op: CausalTreeOp<PlainTextOperation>, opIdx: number) {
|
||||
#applyCacheUpdate(op: CausalTreeOp<PlainTextOperation>, opIdx: number): [number, number] {
|
||||
for (let i = 0; i < this.opIndexCache.length; i++) {
|
||||
if (this.opIndexCache[i] >= opIdx) {
|
||||
this.opIndexCache[i] += 1;
|
||||
|
@ -37,20 +42,36 @@ export class PlainTextORDT extends CausalTree<PlainTextOperation> {
|
|||
const parentCacheIdx = this.timestamps.findIndex(it => it === parentTimestamp);
|
||||
|
||||
if (op.type === "insert") {
|
||||
let idx = parentCacheIdx + 1;
|
||||
for (; idx < this.timestamps.length; idx++) {
|
||||
const curr = this.timestamps[idx];
|
||||
let cacheIdx = parentCacheIdx + 1;
|
||||
for (; cacheIdx < this.timestamps.length; cacheIdx++) {
|
||||
const curr = this.timestamps[cacheIdx];
|
||||
if (timestampCompare(curr, op.at) < 0) break;
|
||||
}
|
||||
|
||||
this.sequences.splice(idx, 0, op.sequence);
|
||||
this.timestamps.splice(idx, 0, op.at);
|
||||
this.deleted.splice(idx, 0, false);
|
||||
this.opIndexCache.splice(idx, 0, opIdx);
|
||||
this.sequences.splice(cacheIdx, 0, op.sequence);
|
||||
this.timestamps.splice(cacheIdx, 0, op.at);
|
||||
this.deleted.splice(cacheIdx, 0, false);
|
||||
this.opIndexCache.splice(cacheIdx, 0, opIdx);
|
||||
|
||||
let textIndex = 0;
|
||||
for (let i = 0; i < cacheIdx; i++) {
|
||||
if (this.deleted[i]) continue;
|
||||
textIndex += this.sequences[i].length;
|
||||
}
|
||||
return [textIndex, op.sequence.length];
|
||||
}
|
||||
if (op.type === "delete" && parentCacheIdx !== -1) {
|
||||
this.deleted[parentCacheIdx] = true;
|
||||
|
||||
let textIndex = 0;
|
||||
for (let i = 0; i < parentCacheIdx; i++) {
|
||||
if (this.deleted[i]) continue;
|
||||
textIndex += this.sequences[i].length;
|
||||
}
|
||||
return [textIndex, -this.sequences[parentCacheIdx].length];
|
||||
}
|
||||
|
||||
return [-1, 0];
|
||||
}
|
||||
|
||||
findOpAtTextIndex(textIndex: number): number {
|
||||
|
|
Loading…
Reference in a new issue