text: import { getHandlers } from "./event"
  
  let operationGroup = null
  
  export function pushOperation(op) {
    if (operationGroup) {
      operationGroup.ops.push(op)
    } else {
      op.ownsGroup = operationGroup = {
        ops: [op],
        delayedCallbacks: []
      }
    }
  }
  
  function fireCallbacksForOps(group) {
    // Calls delayed callbacks and cursorActivity handlers until no
    // new ones appear
    let callbacks = group.delayedCallbacks, i = 0
    do {
      for (; i < callbacks.length; i++)
        callbacks[i].call(null)
      for (let j = 0; j < group.ops.length; j++) {
        let op = group.ops[j]
        if (op.cursorActivityHandlers)
          while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
            op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm)
      }
    } while (i < callbacks.length)
  }
  
  export function finishOperation(op, endCb) {
    let group = op.ownsGroup
    if (!group) return
  
    try { fireCallbacksForOps(group) }
    finally {
      operationGroup = null
      endCb(group)
    }
  }
  
  let orphanDelayedCallbacks = null
  
  // Often, we want to signal events at a point where we are in the
  // middle of some work, but don't want the handler to start calling
  // other methods on the editor, which might be in an inconsistent
  // state or simply not expect any other events to happen.
  // signalLater looks whether there are any handlers, and schedules
  // them to be executed when the last operation ends, or, if no
  // operation is active, when a timeout fires.
  export function signalLater(emitter, type /*, values...*/) {
    let arr = getHandlers(emitter, type, false)
    if (!arr.length) return
    let args = Array.prototype.slice.call(arguments, 2), list
    if (operationGroup) {
      list = operationGroup.delayedCallbacks
    } else if (orphanDelayedCallbacks) {
      list = orphanDelayedCallbacks
    } else {
      list = orphanDelayedCallbacks = []
      setTimeout(fireOrphanDelayed, 0)
    }
    for (let i = 0; i < arr.length; ++i)
      list.push(() => arr[i].apply(null, args))
  }
  
  function fireOrphanDelayed() {
    let delayed = orphanDelayedCallbacks
    orphanDelayedCallbacks = null
    for (let i = 0; i < delayed.length; ++i) delayed[i]()
  }
  