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,11 +19,13 @@ const setup = () => {
test('can insert markers', () => {
const {peritext} = setup();
const {editor} = peritext;
expect(size(peritext.overlay.root)).toBe(0);
expect([...peritext.overlay].length).toBe(0);
editor.cursor.setAt(0);
peritext.refresh();
expect([...peritext.overlay].length).toBe(1);
editor.insMarker(['p'], '<p>');
peritext.refresh();
expect(size(peritext.overlay.root)).toBe(1);
expect(size(peritext.overlay.root)).toBe(2);
editor.cursor.setAt(9);
editor.insMarker(['p'], '<p>');
peritext.refresh();
Expand Down
51 changes: 51 additions & 0 deletions src/json-crdt-extensions/peritext/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {s} from '../../../json-crdt-patch';
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'),
});
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');
const api = model.api;
const peritextApi = model.s.text.toExt();
const peritext = peritextApi.txt;
const editor = peritextApi.editor;
return {
schema,
model,
api,
peritextApi,
peritext,
editor,
};
};
15 changes: 15 additions & 0 deletions src/json-crdt-extensions/peritext/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ export const enum Chars {
BlockSplitSentinel = '\n',
}

export const enum Position {
/**
* Specifies the absolute start of the text, i.e. the position before the
* first character. In model space it is defined as string ID and "after"
* anchor.
*/
AbsStart = -1,

/**
* Specifies the absolute end of the text, i.e. the position after the last
* character. In model space it is defined as string ID and "before" anchor.
*/
AbsEnd = 9007199254740991, // Number.MAX_SAFE_INTEGER
}

export const MNEMONIC = ExtensionName[ExtensionId.peritext];

export const SCHEMA = (text: string) =>
Expand Down
5 changes: 4 additions & 1 deletion src/json-crdt-extensions/peritext/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,25 @@ export class Editor<T = string> {
return true;
}

/** @deprecated use `.saved.insStack` */
public insStackSlice(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T> {
const range = this.cursor.range();
return this.txt.savedSlices.ins(range, SliceBehavior.Stack, type, data);
}

/** @deprecated use `.saved.insOverwrite` */
public insOverwriteSlice(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T> {
const range = this.cursor.range();
return this.txt.savedSlices.ins(range, SliceBehavior.Overwrite, type, data);
}

/** @deprecated use `.saved.insErase` */
public insEraseSlice(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T> {
const range = this.cursor.range();
return this.txt.savedSlices.ins(range, SliceBehavior.Erase, type, data);
}

/** @deprecated */
/** @deprecated use `.saved.insMarker` */
public insMarker(type: SliceType, data?: unknown): MarkerSlice<T> {
return this.saved.insMarker(type, data, Chars.BlockSplitSentinel)[0];
}
Expand Down
33 changes: 27 additions & 6 deletions src/json-crdt-extensions/peritext/editor/EditorSlices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,44 @@ import type {Peritext} from '../Peritext';
import type {SliceType} from '../slice/types';
import type {MarkerSlice} from '../slice/MarkerSlice';
import type {Slices} from '../slice/Slices';
import type {ITimestampStruct} from '../../../json-crdt-patch';
import type {PersistedSlice} from '../slice/PersistedSlice';
import type {Cursor} from './Cursor';

export class EditorSlices<T = string> {
constructor(
protected readonly txt: Peritext<T>,
protected readonly slices: Slices<T>,
) {}

protected insAtCursors<S extends PersistedSlice<T>>(callback: (cursor: Cursor<T>) => S): S[] {
const slices: S[] = [];
this.txt.editor.cursors((cursor) => {
const slice = callback(cursor);
slices.push(slice);
});
return slices;
}

public insStack(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T>[] {
return this.insAtCursors((cursor) => this.slices.insStack(cursor.range(), type, data));
}

public insOverwrite(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T>[] {
return this.insAtCursors((cursor) => this.slices.insOverwrite(cursor.range(), type, data));
}

public insErase(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice<T>[] {
return this.insAtCursors((cursor) => this.slices.insErase(cursor.range(), type, data));
}

public insMarker(type: SliceType, data?: unknown, separator?: string): MarkerSlice<T>[] {
const {txt, slices} = this;
const markers: MarkerSlice<T>[] = [];
txt.editor.cursors((cursor) => {
return this.insAtCursors((cursor) => {
cursor.collapse();
const after = cursor.start.clone();
after.refAfter();
const marker = slices.insMarkerAfter(after.id, type, data, separator);
markers.push(marker);
const marker = this.slices.insMarkerAfter(after.id, type, data, separator);
return marker;
});
return markers;
}
}
11 changes: 10 additions & 1 deletion src/json-crdt-extensions/peritext/overlay/MarkerOverlayPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ export class MarkerOverlayPoint<T = string> extends OverlayPoint<T> {
}

public toString(tab: string = '', lite?: boolean): string {
return super.toString(tab, lite) + (lite ? '' : printTree(tab, [(tab) => this.marker.toString(tab)]));
return (
this.toStringName(tab, lite) +
(lite
? ''
: printTree(tab, [
(tab) => this.marker.toString(tab),
...this.layers.map((slice) => (tab: string) => slice.toString(tab)),
...this.markers.map((slice) => (tab: string) => slice.toString(tab)),
]))
);
}
}
Loading