typeObserver = (binding, event) => {
  binding._mux(() => {
    const cmDoc = binding.cmDoc;
    const cm = cmDoc.getEditor(); // Normally the position is right-associated
    // But when remote changes happen, it looks like the remote user is hijacking your position.
    // Just for remote insertions, we make the collapsed cursor left-associated.
    // If selection is not collapsed, we only make "to" left associated

    let anchor = cm.indexFromPos(cm.getCursor('anchor'));
    let head = cm.indexFromPos(cm.getCursor('head'));
    const switchSel = head < anchor; // normalize selection so that anchor < head, switch back later

    if (switchSel) {
      const tmp = head;
      head = anchor;
      anchor = tmp;
    }

    const performChange = () => {
      const delta = event.delta;
      let index = 0;

      for (let i = 0; i < event.delta.length; i++) {
        const d = delta[i];

        if (d.retain) {
          index += d.retain;
        } else if (d.insert) {
          if (index < anchor || anchor < head && index === anchor) {
            anchor += d.insert.length;
          }

          if (index < head) {
            head += d.insert.length;
          }

          const pos = cmDoc.posFromIndex(index);
          cmDoc.replaceRange(d.insert, pos, pos, cmOrigin);
          index += d.insert.length;
        } else if (d.delete) {
          if (index < anchor) {
            anchor = math.max(anchor - d.delete, index);
          }

          if (index < head) {
            head = math.max(head - d.delete, index);
          }

          const start = cmDoc.posFromIndex(index);
          const end = cmDoc.posFromIndex(index + d.delete);
          cmDoc.replaceRange('', start, end, cmOrigin);
        }
      }
    }; // if possible, bundle the changes using cm.operation


    if (cm) {
      cm.operation(performChange);
    } else {
      performChange();
    }

    if (switchSel) {
      const tmp = head;
      head = anchor;
      anchor = tmp;
    }

    cm.setSelection(cm.posFromIndex(anchor), cm.posFromIndex(head), {
      scroll: false
    });
  });
}
@param {CodemirrorBinding} binding
@param {any} event