Skip to content

Commit

Permalink
feat(json-crdt-extensions): 馃幐 add higher-level API for inserting markers
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Apr 29, 2024
1 parent deb028f commit 7789ced
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 15 deletions.
4 changes: 0 additions & 4 deletions src/json-crdt-extensions/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,3 @@ export const enum ExtensionId {
peritext = 2,
quill = 3,
}

export const enum Chars {
BlockSplitSentinel = '\n',
}
42 changes: 31 additions & 11 deletions src/json-crdt-extensions/peritext/Peritext.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import {printTree} from 'sonic-forest/lib/print/printTree';
import {Anchor} from './rga/constants';
import {Point} from './rga/Point';
import {Range} from './rga/Range';
import {Editor} from './editor/Editor';
import {printTree} from '../../util/print/printTree';
import {ArrNode, StrNode} from '../../json-crdt/nodes';
import {Slices} from './slice/Slices';
import {type ITimestampStruct} from '../../json-crdt-patch/clock';
import {Overlay} from './overlay/Overlay';
import {Chars} from './constants';
import type {ITimestampStruct} from '../../json-crdt-patch/clock';
import type {Model} from '../../json-crdt/model';
import type {Printable} from '../../util/print/types';
import type {StringChunk} from './util/types';
import type {SliceType} from './types';
import type {MarkerSlice} from './slice/MarkerSlice';

/**
* Context for a Peritext instance. Contains all the data and methods needed to
Expand All @@ -17,6 +21,7 @@ import type {StringChunk} from './util/types';
export class Peritext implements Printable {
public readonly slices: Slices;
public readonly editor: Editor;
public readonly overlay = new Overlay(this);

constructor(
public readonly model: Model,
Expand All @@ -43,6 +48,17 @@ export class Peritext implements Printable {
return curr;
}

/** Select a single character before a point. */
public findCharBefore(point: Point): Range | undefined {
if (point.anchor === Anchor.After) {
const chunk = point.chunk();
if (chunk && !chunk.del) return this.range(this.point(point.id, Anchor.Before), point);
}
const id = point.prevId();
if (!id) return;
return this.range(this.point(id, Anchor.Before), this.point(id, Anchor.After));
}

// ------------------------------------------------------------------- points

/**
Expand Down Expand Up @@ -159,15 +175,19 @@ export class Peritext implements Printable {
return textId;
}

/** Select a single character before a point. */
public findCharBefore(point: Point): Range | undefined {
if (point.anchor === Anchor.After) {
const chunk = point.chunk();
if (chunk && !chunk.del) return this.range(this.point(point.id, Anchor.Before), point);
}
const id = point.prevId();
if (!id) return;
return this.range(this.point(id, Anchor.Before), this.point(id, Anchor.After));
public insMarker(after: ITimestampStruct, type: SliceType, data?: unknown, char: string = Chars.BlockSplitSentinel): MarkerSlice {
const api = this.model.api;
const builder = api.builder;
const str = this.str;
/**
* We skip one clock cycle to prevent Block-wise RGA from merging adjacent
* characters. We want the marker chunk to always be its own distinct chunk.
*/
builder.nop(1);
const textId = builder.insStr(str.id, after, char[0]);
const point = this.point(textId, Anchor.Before);
const range = this.range(point, point);
return this.slices.insMarker(range, type, data);
}

// ---------------------------------------------------------------- Printable
Expand Down
3 changes: 3 additions & 0 deletions src/json-crdt-extensions/peritext/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const enum Chars {
BlockSplitSentinel = '\n',
}
7 changes: 7 additions & 0 deletions src/json-crdt-extensions/peritext/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import {Anchor} from '../rga/constants';
import {SliceBehavior} from '../slice/constants';
import {tick, type ITimestampStruct} from '../../../json-crdt-patch/clock';
import {PersistedSlice} from '../slice/PersistedSlice';
import {Chars} from '../constants';
import type {Range} from '../rga/Range';
import type {Peritext} from '../Peritext';
import type {Printable} from '../../../util/print/types';
import type {Point} from '../rga/Point';
import type {SliceType} from '../types';
import type {MarkerSlice} from '../slice/MarkerSlice';

export class Editor implements Printable {
/**
Expand Down Expand Up @@ -132,4 +134,9 @@ export class Editor implements Printable {
public insertEraseSlice(type: SliceType, data?: unknown | ITimestampStruct): PersistedSlice {
return this.txt.slices.ins(this.cursor, SliceBehavior.Erase, type, data);
}

public insMarker(type: SliceType, data?: unknown): MarkerSlice {
const after = this.collapseSelection();
return this.txt.insMarker(after, type, data, Chars.BlockSplitSentinel);
}
}

0 comments on commit 7789ced

Please sign in to comment.