Skip to content

Commit

Permalink
feat(json-crdt-extensions): 🎸 improve deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Nov 11, 2024
1 parent 10bdf3d commit 59ec4eb
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -220,17 +220,17 @@ runInlineSlicesTests('text with block split', (editor: Editor) => {
runInlineSlicesTests('text with deletes', (editor: Editor) => {
editor.insert('lmXXXnwYxyz');
editor.cursor.setAt(2, 3);
editor.cursor.del();
editor.del();
editor.cursor.setAt(3);
editor.insert('opqrstuv');
editor.cursor.setAt(12, 1);
editor.cursor.del();
editor.del();
editor.cursor.setAt(0);
editor.insert('ab1c3defghijk4444');
editor.cursor.setAt(2, 1);
editor.cursor.del();
editor.del();
editor.cursor.setAt(3, 1);
editor.cursor.del();
editor.del();
editor.cursor.setAt(11, 4);
editor.cursor.del();
editor.del();
});
30 changes: 2 additions & 28 deletions src/json-crdt-extensions/peritext/editor/Cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export class Cursor<T = string> extends PersistedSlice<T> {
}

/**
* @deprecated Use `Editor.insert()` instead.
*
* Insert inline text at current cursor position. If cursor selects a range,
* the range is removed and the text is inserted at the start of the range.
*/
Expand All @@ -99,34 +101,6 @@ export class Cursor<T = string> extends PersistedSlice<T> {
this.setAfter(shift ? tick(textId, shift) : textId);
}

/**
* Deletes the given number of characters from the current caret position.
* Negative values delete backwards. If the cursor selects a range, the
* range is removed and the cursor is set at the start of the range.
*
* @param step Number of characters to delete. Negative values delete
* backwards.
*/
public del(step: number = -1): void {
if (!this.isCollapsed()) {
this.collapse();
return;
}
const point1 = this.start.clone();
const point2 = point1.clone();
if (step > 0) point2.step(1);
else if (step < 0) point1.step(-1);
else if (step === 0) {
point1.step(-1);
point2.step(1);
}
const txt = this.txt;
const range = txt.range(point1, point2);
txt.delStr(range);
point1.refAfter();
this.set(point1);
}

// ---------------------------------------------------------------- Printable

public toStringName(): string {
Expand Down
39 changes: 16 additions & 23 deletions src/json-crdt-extensions/peritext/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,15 @@ export class Editor<T = string> implements Printable {
* select a range, deletes the whole range.
*/
public del(step: number = -1): void {
this.forCursor((cursor) => cursor.del(step));
this.delete(step, 'char');
}

public delRange(range: Range<T>): void {
const txt = this.txt;
const overlay = txt.overlay;
const contained = overlay.findContained(range);
for (const slice of contained) if (slice instanceof PersistedSlice) slice.del();
txt.delStr(range);
}

/**
Expand All @@ -160,7 +168,8 @@ export class Editor<T = string> implements Printable {
* @param unit A unit of deletion: "char", "word", "line".
*/
public delete(step: number, unit: 'char' | 'word' | 'line'): void {
this.forCursor((cursor) => {
const txt = this.txt;
for (let i = this.cursors0(), cursor = i(); cursor; cursor = i()) {
if (!cursor.isCollapsed()) {
cursor.collapse();
return;
Expand All @@ -173,12 +182,11 @@ export class Editor<T = string> implements Printable {
point1 = this.skip(point1, -1, unit);
point2 = this.skip(point2, 1, unit);
}
const txt = this.txt;
const range = txt.range(point1, point2);
txt.delStr(range);
this.delRange(range);
point1.refAfter();
cursor.set(point1);
});
}
}

// ----------------------------------------------------------------- movement
Expand Down Expand Up @@ -506,14 +514,6 @@ export class Editor<T = string> implements Printable {

// --------------------------------------------------------------- formatting

protected getSliceStore(slice: PersistedSlice<T>): EditorSlices<T> | undefined {
const sid = slice.id.sid;
if (sid === this.saved.slices.set.doc.clock.sid) return this.saved;
if (sid === this.extra.slices.set.doc.clock.sid) return this.extra;
if (sid === this.local.slices.set.doc.clock.sid) return this.local;
return;
}

protected toggleRangeExclFmt(
range: Range<T>,
type: CommonSliceType | string | number,
Expand All @@ -527,12 +527,8 @@ export class Editor<T = string> implements Printable {
const needToRemoveFormatting = complete.has(type);
makeRangeExtendable(range);
const contained = overlay.findContained(range);
for (const slice of contained) {
if (slice instanceof PersistedSlice && slice.type === type) {
const deletionStore = this.getSliceStore(slice);
if (deletionStore) deletionStore.del(slice.id);
}
}
for (const slice of contained)
if (slice instanceof PersistedSlice && slice.type === type) slice.del();
if (needToRemoveFormatting) {
overlay.refresh();
const [complete2, partial2] = overlay.stat(range, 1e6);
Expand Down Expand Up @@ -584,10 +580,7 @@ export class Editor<T = string> implements Printable {
switch (slice.behavior) {
case SliceBehavior.One:
case SliceBehavior.Many:
case SliceBehavior.Erase: {
const deletionStore = this.getSliceStore(slice);
if (deletionStore) deletionStore.del(slice.id);
}
case SliceBehavior.Erase: slice.del();
}
}
}
Expand Down
21 changes: 20 additions & 1 deletion src/json-crdt-extensions/peritext/slice/PersistedSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
} from './constants';
import {CONST} from '../../../json-hash';
import {Timestamp} from '../../../json-crdt-patch/clock';
import type {VecNode} from '../../../json-crdt/nodes';
import {prettyOneLine} from '../../../json-pretty';
import {validateType} from './util';
import {s} from '../../../json-crdt-patch';
import type {VecNode} from '../../../json-crdt/nodes';
import type {ITimestampStruct} from '../../../json-crdt-patch/clock';
import type {ArrChunk} from '../../../json-crdt/nodes';
import type {MutableSlice, SliceView, SliceType, SliceUpdateParams} from './types';
Expand All @@ -26,6 +26,7 @@ import type {Printable} from 'tree-dump/lib/types';
import type {AbstractRga} from '../../../json-crdt/nodes/rga';
import type {Model} from '../../../json-crdt/model';
import type {Peritext} from '../Peritext';
import type {Slices} from './Slices';

/**
* A persisted slice is a slice that is stored in a {@link Model}. It is used for
Expand Down Expand Up @@ -145,6 +146,24 @@ export class PersistedSlice<T = string> extends Range<T> implements MutableSlice
return node && this.model.api.wrap(node);
}

public getStore(): Slices<T> | undefined {
const txt = this.txt;
const sid = this.id.sid;
let store = txt.savedSlices;
if (sid === store.set.doc.clock.sid) return store;
store = txt.localSlices;
if (sid === store.set.doc.clock.sid) return store;
store = txt.extraSlices;
if (sid === store.set.doc.clock.sid) return store;
return;
}

public del(): void {
const store = this.getStore();
if (!store) return;
store.del(this.id);
}

public isDel(): boolean {
return this.chunk.del;
}
Expand Down
5 changes: 5 additions & 0 deletions src/json-crdt-extensions/peritext/slice/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ export interface Slice<T = string> extends Range<T>, Stateful {
export interface MutableSlice<T = string> extends Slice<T> {
update(params: SliceUpdateParams<T>): void;

/**
* Delete this slice from its backing store.
*/
del(): void;

/**
* Whether the slice is deleted.
*/
Expand Down

0 comments on commit 59ec4eb

Please sign in to comment.