All files / json-crdt-peritext-ui/events/defaults annals.ts

14.81% Statements 4/27
0% Branches 0/9
0% Functions 0/1
12.5% Lines 3/24

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  5x 5x                     5x                                                      
import type {Peritext} from '../../../json-crdt-extensions';
import {Anchor} from '../../../json-crdt-extensions/peritext/rga/constants';
import {DelOp, equal, InsArrOp, InsBinOp, InsStrOp, type Patch, Timestamp} from '../../../json-crdt-patch';
import type {Range} from '../../../json-crdt-extensions/peritext/rga/Range';
 
/**
 * Given an undo/redo patch/batch, calculates a good cursor position to place
 * the cursor after the patch is applied, so that the user can continue typing
 * from the same logical position.
 *
 * @param patch Undo/Redo patch
 * @returns Range
 */
export const placeCursor = (txt: Peritext, batch: Patch[]): Range | undefined => {
  const batchLength = batch.length;
  for (let j = batchLength - 1; j >= 0; j--) {
    const patch = batch[j];
    const ops = patch.ops;
    const length = ops.length;
    for (let i = length - 1; i >= 0; i--) {
      const op = ops[i];
      if (op instanceof InsStrOp || op instanceof InsBinOp || op instanceof InsArrOp) {
        const opId = op.id;
        const lastCharId = new Timestamp(opId.sid, opId.time + op.span() - 1);
        const point = txt.point(lastCharId, Anchor.After);
        const cursor = txt.range(point);
        return cursor;
      } else Iif (op instanceof DelOp && equal(op.obj, txt.str.id)) {
        const lastSpan = op.what[op.what.length - 1];
        Iif (lastSpan) {
          const point = txt.point(lastSpan, Anchor.Before);
          point.halfstep(-1);
          const cursor = txt.range(point);
          return cursor;
        }
      }
    }
  }
  return;
};