       else
         @position.column += output.length
 
-    @bufferedSourcePositions.push(@sourcePosition.copy())
-    @bufferedPositions.push(@position.copy())
-    @bufferedOutputs.push(output)
+    @bufferedOutputs.push(
+      content: output
+      position: @position.copy()
+      sourcePosition: @sourcePosition.copy()
+    )

    @reset(Point.zero(), Point.zero())

  reset: (position, sourcePosition) ->
    @sourceIterator.seek(sourcePosition)
    @position = position
    @sourcePosition = sourcePosition
    @bufferedSourceOutput = null
    @bufferedOutputs = []
    @bufferedPositions = []
    @bufferedSourcePositions = []

  read: =>
    @bufferedSourceOutput ?= @sourceIterator.next().value

  consume: (count) =>
    @sourcePosition.column += count
    @bufferedSourceOutput = @bufferedSourceOutput.slice(count)
    @bufferedSourceOutput = null if @bufferedSourceOutput is ""

  produce: (output) =>
    switch output

    return if position.isZero()

    until @sourcePosition.compare(position) >= 0
      lastPosition = @position
      lastSourcePosition = @sourcePosition
      {done} = @next()
      break if done

    overshoot = position.column - lastSourcePosition.column
    lastPosition.column += overshoot
    @transformDelegate.reset(lastPosition, position)
    @position = lastPosition
    @sourcePosition = position

  getPosition: ->
