     @editor.createFold(range.start.row, range.end.row)
     @cursor.setBufferPosition([range.end.row + 1, 0])
 
-  modifySelection: (fn) ->
-    @retainSelection = true
-    @plantTail()
-    fn()
-    @retainSelection = false
-
-  # Sets the marker's tail to the same position as the marker's head.
-  #
-  # This only works if there isn't already a tail position.
-  #
-  # Returns a {Point} representing the new tail position.
-  plantTail: ->
-    @marker.plantTail()
-
-  # Public: Identifies if a selection intersects with a given buffer range.
-  #
-  # * `bufferRange` A {Range} to check against.
-  #
-  # Returns a {Boolean}
-  intersectsBufferRange: (bufferRange) ->
-    @getBufferRange().intersectsWith(bufferRange)
-
-  intersectsScreenRowRange: (startRow, endRow) ->
-    @getScreenRange().intersectsRowRange(startRow, endRow)
-
-  intersectsScreenRow: (screenRow) ->
-    @getScreenRange().intersectsRow(screenRow)
-
-  # Public: Identifies if a selection intersects with another selection.
-  #
-  # * `otherSelection` A {Selection} to check against.
-  #
-  # Returns a {Boolean}
-  intersectsWith: (otherSelection, exclusive) ->
-    @getBufferRange().intersectsWith(otherSelection.getBufferRange(), exclusive)
+  # Public: Indents the given text to the suggested level based on the grammar.
+  #
+  # * `text` The {String} to indent within the selection.
+  # * `indentBasis` The beginning indent level.
+  normalizeIndents: (text, indentBasis) ->
+    textPrecedingCursor = @cursor.getCurrentBufferLine()[0...@cursor.getBufferColumn()]
+    isCursorInsideExistingLine = /\S/.test(textPrecedingCursor)
+
+    lines = text.split('\n')
+    firstLineIndentLevel = @editor.indentLevelForLine(lines[0])
+    if isCursorInsideExistingLine
+      minimumIndentLevel = @editor.indentationForBufferRow(@cursor.getBufferRow())
+    else
+      minimumIndentLevel = @cursor.getIndentLevel()
+
+    normalizedLines = []
+    for line, i in lines
+      if i == 0
+        indentLevel = 0
+      else if line == '' # remove all indentation from empty lines
+        indentLevel = 0
+      else
+        lineIndentLevel = @editor.indentLevelForLine(lines[i])
+        indentLevel = minimumIndentLevel + (lineIndentLevel - indentBasis)
+
+      normalizedLines.push(@setIndentationForLine(line, indentLevel))
+
+    normalizedLines.join('\n')
+
+  # Indent the current line(s).
+  #
+  # If the selection is empty, indents the current line if the cursor precedes
+  # non-whitespace characters, and otherwise inserts a tab. If the selection is
+  # non empty, calls {::indentSelectedRows}.
+  #
+  # * `options` (optional) {Object} with the keys:
+  #   * `autoIndent` If `true`, the line is indented to an automatically-inferred
+  #     level. Otherwise, {Editor::getTabText} is inserted.
+  indent: ({ autoIndent }={}) ->
+    { row, column } = @cursor.getBufferPosition()
+
+    if @isEmpty()
+      @cursor.skipLeadingWhitespace()
+      desiredIndent = @editor.suggestedIndentForBufferRow(row)
+      delta = desiredIndent - @cursor.getIndentLevel()
+
+      if autoIndent and delta > 0
+        @insertText(@editor.buildIndentString(delta))
+      else
+        @insertText(@editor.buildIndentString(1, @cursor.getBufferColumn()))
+    else
+      @indentSelectedRows()
+
+  # Public: If the selection spans multiple rows, indent all of them.
+  indentSelectedRows: ->
+    [start, end] = @getBufferRowRange()
+    for row in [start..end]
+      @editor.buffer.insert([row, 0], @editor.getTabText()) unless @editor.buffer.lineLengthForRow(row) == 0
+
+  setIndentationForLine: (line, indentLevel) ->
+    desiredIndentLevel = Math.max(0, indentLevel)
+    desiredIndentString = @editor.buildIndentString(desiredIndentLevel)
+    line.replace(/^[\t ]*/, desiredIndentString)
+
+  ###
+  Section: Managing multiple selections
+  ###
+
+  # Public: Moves the selection down one row.
+  addSelectionBelow: ->
+    range = (@getGoalBufferRange() ? @getBufferRange()).copy()
+    nextRow = range.end.row + 1
+
+    for row in [nextRow..@editor.getLastBufferRow()]
+      range.start.row = row
+      range.end.row = row
+      clippedRange = @editor.clipBufferRange(range)
+
+      if range.isEmpty()
+        continue if range.end.column > 0 and clippedRange.end.column is 0
+      else
+        continue if clippedRange.isEmpty()
+
+      @editor.addSelectionForBufferRange(range, goalBufferRange: range)
+      break
+
+  # Public: Moves the selection up one row.
+  addSelectionAbove: ->
+    range = (@getGoalBufferRange() ? @getBufferRange()).copy()
+    previousRow = range.end.row - 1
+
+    for row in [previousRow..0]
+      range.start.row = row
+      range.end.row = row
+      clippedRange = @editor.clipBufferRange(range)
+
+      if range.isEmpty()
+        continue if range.end.column > 0 and clippedRange.end.column is 0
+      else
+        continue if clippedRange.isEmpty()
+
+      @editor.addSelectionForBufferRange(range, goalBufferRange: range)
+      break
 
   # Public: Combines the given selection into this selection and then destroys
   # the given selection.


    super

  ###
  Section: Methods
  ###

  destroy: ->
    @marker.destroy()

  finalize: ->
    @initialScreenRange = null unless @initialScreenRange?.isEqual(@getScreenRange())
    if @isEmpty()
      @wordwise = false
      @linewise = false

  clearAutoscroll: ->
    @needsAutoscroll = null

  # Public: Determines if the selection contains anything.
  isEmpty: ->
    @getBufferRange().isEmpty()

  # Public: Determines if the ending position of a marker is greater than the
  # starting position.
  #
  # This can happen when, for example, you highlight text "up" in a {TextBuffer}.
  isReversed: ->
    @marker.isReversed()

  # Public: Returns whether the selection is a single line or not.
  isSingleScreenLine: ->
    @getScreenRange().isSingleLine()

  # Public: Returns the screen {Range} for the selection.
  getScreenRange: ->

    @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options)
    otherSelection.destroy()

  ###
  Section: Comparing to other selections
  ###

  # Public: Compare this selection's buffer range to another selection's buffer
  # range.
  #
