Skip to content

Commit

Permalink
fix(json-crdt-extensions): 🐛 recompute different Overlay state hash…
Browse files Browse the repository at this point in the history
… when text changes
  • Loading branch information
streamich committed May 8, 2024
1 parent 6fa5d41 commit d64b8ab
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 6 deletions.
19 changes: 14 additions & 5 deletions src/json-crdt-extensions/peritext/overlay/Overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,13 @@ export class Overlay<T = string> implements Printable, Stateful {
return result;
}

public isBlockSplit(id: ITimestampStruct): boolean {
/**
* Returns `true` if the current character is a marker sentinel.
*
* @param id ID of the point to check.
* @returns Whether the point is a marker point.
*/
public isMarker(id: ITimestampStruct): boolean {
const point = this.txt.point(id, Anchor.Before);
const overlayPoint = this.getOrNextLower(point);
return (
Expand All @@ -325,7 +331,7 @@ export class Overlay<T = string> implements Printable, Stateful {
hash = this.refreshSlices(hash, txt.savedSlices);
hash = this.refreshSlices(hash, txt.extraSlices);
hash = this.refreshSlices(hash, txt.localSlices);
if (!slicesOnly) this.computeSplitTextHashes();
if (!slicesOnly) hash = this.computeSplitTextHashes(hash);
return (this.hash = hash);
}

Expand Down Expand Up @@ -455,15 +461,15 @@ export class Overlay<T = string> implements Printable, Stateful {

public leadingTextHash: number = 0;

protected computeSplitTextHashes(): void {
protected computeSplitTextHashes(stateTotal: number): number {
const txt = this.txt;
const str = txt.str;
const firstChunk = str.first();
if (!firstChunk) return;
if (!firstChunk) return stateTotal;
let chunk: Chunk<T> | undefined = firstChunk;
let marker: MarkerOverlayPoint<T> | undefined = undefined;
let state: number = CONST.START_STATE;
const i = this.tuples0(undefined);
let state: number = CONST.START_STATE;
for (let pair = i(); pair; pair = i()) {
const [p1, p2] = pair;
// TODO: need to incorporate slice attribute hash here?
Expand All @@ -478,13 +484,15 @@ export class Overlay<T = string> implements Printable, Stateful {
state = updateNum(state, overlayPointHash);
if (p1) {
p1.hash = overlayPointHash;
stateTotal = updateNum(stateTotal, overlayPointHash);
}
if (p2 instanceof MarkerOverlayPoint) {
if (marker) {
marker.textHash = state;
} else {
this.leadingTextHash = state;
}
stateTotal = updateNum(stateTotal, state);
state = CONST.START_STATE;
marker = p2;
}
Expand All @@ -494,6 +502,7 @@ export class Overlay<T = string> implements Printable, Stateful {
} else {
this.leadingTextHash = state;
}
return stateTotal;
}

// ---------------------------------------------------------------- Printable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ describe('Overlay.refresh()', () => {
});
});

describe('cursor', () => {
describe('local slices - cursor', () => {
describe('updates hash', () => {
testRefresh('when cursor char ID changes', (kit, refresh) => {
kit.peritext.editor.cursor.setAt(1);
Expand Down Expand Up @@ -302,4 +302,24 @@ describe('Overlay.refresh()', () => {
});
});
});

describe('text contents', () => {
describe('updates hash', () => {
testRefresh('when the first character is deleted and reinserted', (kit, refresh) => {
const index = 0;
const char = kit.peritext.strApi().view()[index];
refresh();
kit.peritext.strApi().del(index, 1);
kit.peritext.strApi().ins(index, char);
});

testRefresh('when the last character is deleted and reinserted', (kit, refresh) => {
const index = kit.peritext.strApi().view().length - 1;
const char = kit.peritext.strApi().view()[index];
refresh();
kit.peritext.strApi().del(index, 1);
kit.peritext.strApi().ins(index, char);
});
});
});
});

0 comments on commit d64b8ab

Please sign in to comment.