Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ const setup = () => {
test('can insert markers', () => {
const {peritext} = setup();
const {editor} = peritext;
expect([...peritext.overlay].length).toBe(0);
expect([...peritext.overlay.points()].length).toBe(0);
editor.cursor.setAt(0);
peritext.refresh();
expect([...peritext.overlay].length).toBe(1);
editor.insMarker(['p'], '<p>');
expect([...peritext.overlay.points()].length).toBe(1);
editor.saved.insMarker(['p'], '<p>');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(2);
editor.cursor.setAt(9);
editor.insMarker(['p'], '<p>');
editor.saved.insMarker(['p'], '<p>');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(3);
});
Expand All @@ -37,15 +37,15 @@ test('can insert slices', () => {
const {editor} = peritext;
expect(size(peritext.overlay.root)).toBe(0);
editor.cursor.setAt(2, 2);
editor.insStackSlice('bold');
editor.saved.insStack('bold');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(2);
editor.cursor.setAt(6, 5);
editor.insStackSlice('italic');
editor.extra.insStack('italic');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(4);
editor.cursor.setAt(0, 5);
editor.insStackSlice('underline');
editor.local.insStack('underline');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(6);
});
116 changes: 82 additions & 34 deletions src/json-crdt-extensions/peritext/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,22 @@
import {s} from '../../../json-crdt-patch';
import {Model} from '../../../json-crdt/model';
import {SchemaToJsonNode} from '../../../json-crdt/schema/types';
import {ModelWithExt, ext} from '../../ModelWithExt';

/**
* Creates a Peritext instance with text "0123456789", with single-char and
* block-wise chunks, as well as with plenty of tombstones.
*/
export const setupNumbersWithTombstones = () => {
const schema = s.obj({
text: ext.peritext.new('1234'),
export type Schema = ReturnType<typeof schema>;
export type Kit = ReturnType<typeof setupKit>;

const schema = (text: string) =>
s.obj({
text: ext.peritext.new(text),
});
const model = ModelWithExt.create(schema);
const str = model.s.text.toExt().text();
str.ins(1, '234');
str.ins(2, '345');
str.ins(3, '456');
str.ins(4, '567');
str.ins(5, '678');
str.ins(6, '789');
str.del(7, 1);
str.del(8, 1);
str.ins(0, '0');
str.del(1, 4);
str.del(2, 1);
str.ins(1, '1');
str.del(0, 1);
str.ins(0, '0');
str.ins(2, '234');
str.del(4, 7);
str.del(4, 2);
str.del(7, 3);
str.ins(6, '6789');
str.del(7, 2);
str.ins(7, '78');
str.del(10, 2);
str.del(2, 3);
str.ins(2, '234');
if (str.view() !== '0123456789') throw new Error('Invalid text');

export const setupKit = (
initialText: string = '',
edits: (model: Model<SchemaToJsonNode<Schema>>) => void = () => {},
) => {
const model = ModelWithExt.create(schema(initialText));
edits(model);
const api = model.api;
const peritextApi = model.s.text.toExt();
const peritext = peritextApi.txt;
Expand All @@ -49,3 +30,70 @@ export const setupNumbersWithTombstones = () => {
editor,
};
};

export const setupHelloWorldKit = (): Kit => {
return setupKit('', (model) => {
const str = model.s.text.toExt().text();
str.ins(0, 'hello world');
if (str.view() !== 'hello world') throw new Error('Invalid text');
});
};

export const setupHelloWorldWithFewEditsKit = (): Kit => {
return setupKit('', (model) => {
const str = model.s.text.toExt().text();
str.ins(0, 'wworld');
str.ins(0, 'helo ');
str.ins(2, 'l');
str.del(7, 1);
if (str.view() !== 'hello world') throw new Error('Invalid text');
});
};

/**
* Creates a Peritext instance with text "0123456789", no edits.
*/
export const setupNumbersKit = (): Kit => {
return setupKit('', (model) => {
const str = model.s.text.toExt().text();
str.ins(0, '0123456789');
if (str.view() !== '0123456789') throw new Error('Invalid text');
});
};

/**
* Creates a Peritext instance with text "0123456789", with single-char and
* block-wise chunks, as well as with plenty of tombstones.
*/
export const setupNumbersWithTombstonesKit = (): Kit => {
return setupKit('1234', (model) => {
const str = model.s.text.toExt().text();
str.ins(0, '234');
str.ins(1, '234');
str.ins(2, '345');
str.ins(3, '456');
str.ins(4, '567');
str.ins(5, '678');
str.ins(6, '789');
str.del(7, 1);
str.del(8, 1);
str.ins(0, '0');
str.del(1, 4);
str.del(2, 1);
str.ins(1, '1');
str.del(0, 1);
str.ins(0, '0');
str.ins(2, '234');
str.del(4, 7);
str.del(4, 2);
str.del(7, 3);
str.ins(6, '6789');
str.del(7, 2);
str.ins(7, '78');
str.del(10, 2);
str.del(2, 3);
str.ins(2, '234');
str.del(10, 3);
if (str.view() !== '0123456789') throw new Error('Invalid text');
});
};
4 changes: 4 additions & 0 deletions src/json-crdt-extensions/peritext/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import type {MarkerSlice} from '../slice/MarkerSlice';

export class Editor<T = string> {
public readonly saved: EditorSlices<T>;
public readonly extra: EditorSlices<T>;
public readonly local: EditorSlices<T>;

constructor(public readonly txt: Peritext<T>) {
this.saved = new EditorSlices(txt, txt.savedSlices);
this.extra = new EditorSlices(txt, txt.extraSlices);
this.local = new EditorSlices(txt, txt.localSlices);
}

public firstCursor(): Cursor<T> | undefined {
Expand Down
Loading