Skip to content

Commit

Permalink
Merge pull request #610 from streamich/overlay-3
Browse files Browse the repository at this point in the history
Setup the `Overlay` class
  • Loading branch information
streamich authored Apr 30, 2024
2 parents c10ccce + c9c5ae4 commit 7f7d40a
Show file tree
Hide file tree
Showing 13 changed files with 613 additions and 54 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',
}
88 changes: 73 additions & 15 deletions src/json-crdt-extensions/peritext/Peritext.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
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 {interval} from '../../json-crdt-patch/clock';
import {CONST, updateNum} from '../../json-hash';
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 @@ -16,6 +23,7 @@ import type {Printable} from '../../util/print/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 @@ -30,7 +38,30 @@ export class Peritext implements Printable {
return this.model.api.wrap(this.str);
}

// ------------------------------------------------------------------- Points
/** @todo Find a better place for this function. */
public firstVisChunk(): StringChunk | undefined {
const str = this.str;
let curr = str.first();
if (!curr) return;
while (curr.del) {
curr = str.next(curr);
if (!curr) return;
}
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

/**
* Creates a point at a character ID.
Expand Down Expand Up @@ -81,7 +112,7 @@ export class Peritext implements Printable {
return this.point(this.str.id, Anchor.Before);
}

// ------------------------------------------------------------------- Ranges
// ------------------------------------------------------------------- ranges

/**
* Creates a range from two points. The points can be in any order.
Expand Down Expand Up @@ -117,7 +148,7 @@ export class Peritext implements Printable {
return Range.at(this.str, start, length);
}

// --------------------------------------------------------------- Insertions
// --------------------------------------------------------------------- text

/**
* Insert plain text at a view position in the text.
Expand Down Expand Up @@ -146,15 +177,37 @@ 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));
// ------------------------------------------------------------------ markers

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);
}

/** @todo This can probably use .del() */
public delMarker(split: MarkerSlice): void {
const str = this.str;
const api = this.model.api;
const builder = api.builder;
const strChunk = split.start.chunk();
if (strChunk) builder.del(str.id, [interval(strChunk.id, 0, 1)]);
builder.del(this.slices.set.id, [interval(split.id, 0, 1)]);
api.apply();
}

// ---------------------------------------------------------------- Printable
Expand All @@ -169,6 +222,8 @@ export class Peritext implements Printable {
(tab) => this.str.toString(tab),
nl,
(tab) => this.slices.toString(tab),
nl,
(tab) => this.overlay.toString(tab),
])
);
}
Expand All @@ -178,6 +233,9 @@ export class Peritext implements Printable {
public hash: number = 0;

public refresh(): number {
return this.slices.refresh();
let state: number = CONST.START_STATE;
this.overlay.refresh();
state = updateNum(state, this.overlay.hash);
return (this.hash = state);
}
}
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);
}
}
Loading

0 comments on commit 7f7d40a

Please sign in to comment.