All files / json-crdt-extensions/peritext/editor EditorSlices.ts

100% Statements 32/32
90% Branches 9/10
100% Functions 11/11
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 7960x               60x       1737x 1737x 1737x 1737x   1737x     60x   10170x 10170x               182x 182x 182x               589x 589x 589x               16x 16x 16x                 950x 950x 950x 950x 950x 950x 950x 950x 950x         613x      
import {PersistedSlice} from '../slice/PersistedSlice';
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 {Range} from '../rga/Range';
 
const forEachRange = <T, S extends PersistedSlice<T>>(
  selection: Range<T>[] | IterableIterator<Range<T>>,
  callback: (range: Range<T>) => S,
): S[] => {
  const slices: S[] = [];
  for (const cursor of selection) {
    const slice = callback(cursor);
    slices.push(slice);
  }
  return slices;
};
 
export class EditorSlices<T = string> {
  constructor(
    protected readonly txt: Peritext<T>,
    public readonly slices: Slices<T>,
  ) {}
 
  public insStack(
    type: SliceType,
    data?: unknown | ITimestampStruct,
    selection?: Range<T>[] | IterableIterator<Range<T>>,
  ): PersistedSlice<T>[] {
    const {slices, txt} = this;
    selection ||= txt.editor.cursors();
    return forEachRange(selection, (range) => slices.insStack(range.range(), type, data));
  }
 
  public insOne(
    type: SliceType,
    data?: unknown | ITimestampStruct,
    selection?: Range<T>[] | IterableIterator<Range<T>>,
  ): PersistedSlice<T>[] {
    const {slices, txt} = this;
    selection ||= txt.editor.cursors();
    return forEachRange(selection, (range) => slices.insOne(range.range(), type, data));
  }
 
  public insErase(
    type: SliceType,
    data?: unknown | ITimestampStruct,
    selection?: Range<T>[] | IterableIterator<Range<T>>,
  ): PersistedSlice<T>[] {
    const {slices, txt} = this;
    selection ||= txt.editor.cursors();
    return forEachRange(selection, (range) => slices.insErase(range.range(), type, data));
  }
 
  public insMarker(
    type: SliceType,
    data?: unknown,
    separator?: string,
    selection?: Range<T>[] | IterableIterator<Range<T>>,
  ): MarkerSlice<T>[] {
    const {slices, txt} = this;
    const editor = txt.editor;
    selection ||= txt.editor.cursors();
    return forEachRange(selection, (range) => {
      editor.collapseCursor(range);
      const after = range.start.clone();
      after.refAfter();
      const marker = slices.insMarkerAfter(after.id, type, data, separator);
      return marker;
    });
  }
 
  public del(sliceOrId: PersistedSlice<T> | ITimestampStruct): void {
    this.slices.del(sliceOrId instanceof PersistedSlice ? sliceOrId.id : sliceOrId);
  }
}