 
 # Extended: A mutable text container with undo/redo support and the ability to
 # annotate logical regions in the text.
+#
+# ## Working With Aggregated Changes
+#
+# When observing changes to the buffer's textual content, it is important to use
+# change-aggregating methods such as {::onDidChangeText}, {::onDidStopChanging},
+# and {::getChangesSinceCheckpoint} in order to maintain high performance. These
+# methods allows your code to respond to *sets* of changes rather than each
+# individual change.
+#
+# These methods report aggregated buffer updates as arrays of change objects
+# containing the following fields: `oldRange`, `newRange`, `oldText`, and
+# `newText`. The `oldText`, `newText`, and `newRange` fields are
+# self-explanatory, but the interepretation of `oldRange` is more nuanced:
+#
+# The reported `oldRange` is the range of the replaced text in the original
+# contents of the buffer *irrespective of the spatial impact of any other
+# reported change*. So, for example, if you wanted to apply all the changes made
+# in a transaction to a clone of the observed buffer, the easiest approach would
+# be to apply the changes in reverse:
+#
+# ```js
+# buffer1.onDidChangeText(({changes}) => {
+#   for (const {oldRange, newText} of changes.reverse()) {
+#     buffer2.setTextInRange(oldRange, newText)
+#   }
+# })
+#
+# If you needed to apply the changes in the forwards order, you would need to
+# incorporate the impact of preceding changes into the range passed to
+# {::setTextInRange}, as follows:
+#
+# ```js
+# buffer1.onDidChangeText(({changes}) => {
+#   for (const {oldRange, newRange, newText} of changes) {
+#     const rangeToReplace = Range(
+#       newRange.start,
+#       newRange.start.traverse(oldRange.getExtent())
+#     )
+#     buffer2.setTextInRange(rangeToReplace, newText)
+#   }
+# })
+# ```
 module.exports =
 class TextBuffer
   @version: 5

  # Public: Invoke the given callback synchronously when a transaction finishes
  # with a list of all the changes in the transaction.
  #
  # * `callback` {Function} to be called when a transaction finishes.
  #   * `event` {Object} with the following keys:
  #     * `changes` {Array} of patch {Object}s:
  #       * `start` Start {Point} of the change.
  #       * `oldExtent` {Point} difference between the replaced start/end points.
  #       * `newExtent` {Point} difference between the inserted start/end points.
  #       * `oldText` {String} containing the text that was replaced.
  #       * `newText` {String} containing the text that was inserted.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeText: (callback) ->

  #
  # This method can be used to perform potentially expensive operations that
  # don't need to be performed synchronously. If you need to run your callback
  # synchronously, use {::onDidChangeText} instead.
  #
  # * `callback` {Function} to be called when the buffer stops changing.
  #   * `event` {Object} with the following keys:
  #     * `changes` An {Array} containing {Object}s summarizing the aggregated
  #       changes. See *Working With Aggregated Changes* in the description of
  #       the {TextBuffer} class for details.
  #       * `oldRange` The {Range} of the deleted text in the contents of the
  #         buffer as it existed *before* the batch of changes reported by this
  #         event.
  #       * `newRange`: The {Range} of the inserted text in the current contents
  #         of the buffer.
  #       * `oldText`: A {String} representing the deleted text.
  #       * `newText`: A {String} representing the ineserted text.
  #
  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidStopChanging: (callback) ->
