Skip to content

Commit

Permalink
feat(json-crdt-extensions): 🎸 improve slice deletions
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 27, 2024
1 parent 96fb402 commit 6359951
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 17 deletions.
21 changes: 12 additions & 9 deletions src/json-crdt-extensions/peritext/Peritext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export class Peritext<T = string> implements Printable {
return this.range(start, end);
}

// --------------------------------------------------------------------- text
// ---------------------------------------------------------- text (& slices)

/**
* Insert plain text at a view position in the text.
Expand Down Expand Up @@ -247,7 +247,7 @@ export class Peritext<T = string> implements Printable {
}

public del(range: Range<T>): void {
// this.delSlices(range);
this.delSlices(range);
this.delStr(range);
}

Expand All @@ -274,13 +274,16 @@ export class Peritext<T = string> implements Printable {
return true;
}

// public delSlices(range: Range): void {
// this.overlay.refresh();
// range = range.clone();
// range.expand();
// const slices = this.overlay.findContained(range);
// this.slices.delMany(Array.from(slices));
// }
public delSlices(range: Range<T>): void {
this.overlay.refresh();
range = range.range();
range.expand();
const slices = this.overlay.findContained(range);
if (!slices.size) return;
this.savedSlices.delSlices(slices);
this.extraSlices.delSlices(slices);
this.localSlices.delSlices(slices);
}

// public delSlice(sliceId: ITimestampStruct): void {
// this.slices.del(sliceId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,3 @@ test('cursor can move across block boundary forwards', () => {
[SliceTypes.Cursor]: [[[CursorAnchor.Start, void 0]], InlineAttrPos.Collapsed],
});
});

test.todo('moving past text end keeps cursor at text end');
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {setupAlphabetChunkSplitKit, setupAlphabetKit, Kit, setupAlphabetWithDeletesKit, setupAlphabetWithTwoChunksKit} from './setup';

const run = (setup: () => Kit) => {
describe('.delAt()', () => {
test('can delete text', () => {
const {peritext} = setup();
peritext.delAt(0, 1);
peritext.delAt(0, 2);
peritext.delAt(1, 2);
peritext.delAt(3, 15);
peritext.delAt(4, 2);
expect(peritext.str.view()).toBe('dghx');
});

test('deletes slice if it is contained in deletion range', () => {
const {peritext, editor} = setup();
editor.cursor.setAt(2, 2);
editor.saved.insOverwrite('underline');
editor.cursor.setAt(0);
peritext.refresh();
expect(editor.saved.slices.size()).toBe(1);
peritext.delAt(1, 3);
peritext.refresh();
expect(editor.saved.slices.size()).toBe(0);
});

test('does not delete slice if it is only partially contained', () => {
const {peritext, editor} = setup();
editor.cursor.setAt(2, 10);
editor.extra.insOverwrite('underline');
editor.cursor.setAt(0);
peritext.refresh();
expect(peritext.extraSlices.size()).toBe(1);
peritext.delAt(1, 10);
peritext.refresh();
expect(peritext.extraSlices.size()).toBe(1);
peritext.delAt(1, 10);
peritext.refresh();
expect(peritext.extraSlices.size()).toBe(0);
});
});
};

describe('basic alphabet', () => run(setupAlphabetKit));
describe('alphabet with chunk splits', () => run(setupAlphabetChunkSplitKit));
describe('alphabet with deletes', () => run(setupAlphabetWithDeletesKit));
describe('alphabet with two chunks', () => run(setupAlphabetWithTwoChunksKit));
7 changes: 6 additions & 1 deletion src/json-crdt-extensions/peritext/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ export class Editor<T = string> {
* the range is removed and the text is inserted at the start of the range.
*/
public insert(text: string): void {
this.cursors((cursor) => cursor.insert(text));
let cnt = 0;
this.cursors((cursor) => {
cnt++;
cursor.insert(text);
});
if (!cnt) this.cursor.insert(text);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/json-crdt-extensions/peritext/editor/EditorSlices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {Cursor} from './Cursor';
export class EditorSlices<T = string> {
constructor(
protected readonly txt: Peritext<T>,
protected readonly slices: Slices<T>,
public readonly slices: Slices<T>,
) {}

protected insAtCursors<S extends PersistedSlice<T>>(callback: (cursor: Cursor<T>) => S): S[] {
Expand Down
7 changes: 3 additions & 4 deletions src/json-crdt-extensions/peritext/slice/Slices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,16 @@ export class Slices<T = string> implements Stateful, Printable {
api.apply();
}

public delSlices(slices: Slice[]): void {
public delSlices(slices: Iterable<Slice<T>>): void {
const api = this.set.doc.api;
const spans: ITimespanStruct[] = [];
const length = slices.length;
for (let i = 0; i < length; i++) {
const slice = slices[i];
for (const slice of slices) {
if (slice instanceof PersistedSlice) {
const id = slice.id;
spans.push(new Timespan(id.sid, id.time, 1));
}
}
if (!spans.length) return;
api.builder.del(this.set.id, spans);
api.apply();
}
Expand Down

0 comments on commit 6359951

Please sign in to comment.