   getBufferPosition: ->
     @marker.getHeadBufferPosition()
 
-  autoscroll: (options) ->
-    @editor.scrollToScreenRange(@getScreenRange(), options)
+  # Public: Returns the cursor's current screen row.
+  getScreenRow: ->
+    @getScreenPosition().row
+
+  # Public: Returns the cursor's current screen column.
+  getScreenColumn: ->
+    @getScreenPosition().column
+
+  # Public: Retrieves the cursor's current buffer row.
+  getBufferRow: ->
+    @getBufferPosition().row
+
+  # Public: Returns the cursor's current buffer column.
+  getBufferColumn: ->
+    @getBufferPosition().column
+
+  # Public: Returns the cursor's current buffer row of text excluding its line
+  # ending.
+  getCurrentBufferLine: ->
+    @editor.lineTextForBufferRow(@getBufferRow())
+
+  # Public: Returns whether the cursor is at the start of a line.
+  isAtBeginningOfLine: ->
+    @getBufferPosition().column == 0
+
+  # Public: Returns whether the cursor is on the line return character.
+  isAtEndOfLine: ->
+    @getBufferPosition().isEqual(@getCurrentLineBufferRange().end)
+
+  ###
+  Section: Position-dependent cursor properties
+  ###
+
+  # Public: Identifies if the cursor is surrounded by whitespace.
+  #
+  # "Surrounded" here means that the character directly before and after the
+  # cursor are both whitespace.
+  #
+  # Returns a {Boolean}.
+  isSurroundedByWhitespace: ->
+    {row, column} = @getBufferPosition()
+    range = [[row, column - 1], [row, column + 1]]
+    /^\s+$/.test @editor.getTextInBufferRange(range)
+
+  # Public: Returns whether the cursor is currently between a word and non-word
+  # character. The non-word characters are defined by the
+  # `editor.nonWordCharacters` config value.
+  #
+  # This method returns false if the character before or after the cursor is
+  # whitespace.
+  #
+  # Returns a Boolean.
+  isBetweenWordAndNonWord: ->
+    return false if @isAtBeginningOfLine() or @isAtEndOfLine()
+
+    {row, column} = @getBufferPosition()
+    range = [[row, column - 1], [row, column + 1]]
+    [before, after] = @editor.getTextInBufferRange(range)
+    return false if /\s/.test(before) or /\s/.test(after)
+
+    nonWordCharacters = atom.config.get('editor.nonWordCharacters').split('')
+    _.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after)
+
+  # Public: Returns whether this cursor is between a word's start and end.
+  isInsideWord: ->
+    {row, column} = @getBufferPosition()
+    range = [[row, column], [row, Infinity]]
+    @editor.getTextInBufferRange(range).search(@wordRegExp()) == 0
+
+  # Public: Returns the indentation level of the current line.
+  getIndentLevel: ->
+    if @editor.getSoftTabs()
+      @getBufferColumn() / @editor.getTabLength()
+    else
+      @getBufferColumn()
+
+  # Public: Retrieves the grammar's token scopes for the line.
+  #
+  # Returns an {Array} of {String}s.
+  getScopes: ->
+    @editor.scopesForBufferPosition(@getBufferPosition())
+
+  # Public: Returns true if this cursor has no non-whitespace characters before
+  # its current position.
+  hasPrecedingCharactersOnLine: ->
+    bufferPosition = @getBufferPosition()
+    line = @editor.lineTextForBufferRow(bufferPosition.row)
+    firstCharacterColumn = line.search(/\S/)
+
+    if firstCharacterColumn is -1
+      false
+    else
+      bufferPosition.column > firstCharacterColumn
+
+  # Public: Identifies if this cursor is the last in the {Editor}.
+  #
+  # "Last" is defined as the most recently added cursor.
+  #
+  # Returns a {Boolean}.
+  isLastCursor: ->
+    this == @editor.getLastCursor()
+
+  ###
+  Section: Moving the Cursor
+  ###
+
+  # Public: Moves the cursor up one screen row.
+  #
+  # * `rowCount` (optional) {Number} number of rows to move (default: 1)
+  # * `options` (optional) {Object} with the following keys:
+  #   * `moveToEndOfSelection` if true, move to the left of the selection if a
+  #     selection exists.
+  moveUp: (rowCount=1, {moveToEndOfSelection}={}) ->
+    range = @marker.getScreenRange()
+    if moveToEndOfSelection and not range.isEmpty()
+      { row, column } = range.start
+    else
+      { row, column } = @getScreenPosition()
+
+    column = @goalColumn if @goalColumn?
+    @setScreenPosition({row: row - rowCount, column: column})
+    @goalColumn = column
+
+  # Public: Moves the cursor down one screen row.
+  #
+  # * `rowCount` (optional) {Number} number of rows to move (default: 1)
+  # * `options` (optional) {Object} with the following keys:
+  #   * `moveToEndOfSelection` if true, move to the left of the selection if a
+  #     selection exists.
+  moveDown: (rowCount=1, {moveToEndOfSelection}={}) ->
+    range = @marker.getScreenRange()
+    if moveToEndOfSelection and not range.isEmpty()
+      { row, column } = range.end
+    else
+      { row, column } = @getScreenPosition()
+
+    column = @goalColumn if @goalColumn?
+    @setScreenPosition({row: row + rowCount, column: column})
+    @goalColumn = column
+
+  # Public: Moves the cursor left one screen column.
+  #
+  # * `columnCount` (optional) {Number} number of columns to move (default: 1)
+  # * `options` (optional) {Object} with the following keys:
+  #   * `moveToEndOfSelection` if true, move to the left of the selection if a
+  #     selection exists.
+  moveLeft: (columnCount=1, {moveToEndOfSelection}={}) ->
+    range = @marker.getScreenRange()
+    if moveToEndOfSelection and not range.isEmpty()
+      @setScreenPosition(range.start)
+    else
+      {row, column} = @getScreenPosition()
+
+      while columnCount > column and row > 0
+        columnCount -= column
+        column = @editor.lineTextForScreenRow(--row).length
+        columnCount-- # subtract 1 for the row move
+
+      column = column - columnCount
+      @setScreenPosition({row, column})
+
+  # Public: Moves the cursor right one screen column.
+  #
+  # * `columnCount` (optional) {Number} number of columns to move (default: 1)
+  # * `options` (optional) {Object} with the following keys:
+  #   * `moveToEndOfSelection` if true, move to the right of the selection if a
+  #     selection exists.
+  moveRight: (columnCount=1, {moveToEndOfSelection}={}) ->
+    range = @marker.getScreenRange()
+    if moveToEndOfSelection and not range.isEmpty()
+      @setScreenPosition(range.end)
+    else
+      { row, column } = @getScreenPosition()
+      maxLines = @editor.getScreenLineCount()
+      rowLength = @editor.lineTextForScreenRow(row).length
+      columnsRemainingInLine = rowLength - column
+
+      while columnCount > columnsRemainingInLine and row < maxLines - 1
+        columnCount -= columnsRemainingInLine
+        columnCount-- # subtract 1 for the row move
+
+        column = 0
+        rowLength = @editor.lineTextForScreenRow(++row).length
+        columnsRemainingInLine = rowLength
+
+      column = column + columnCount
+      @setScreenPosition({row, column}, skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
+
+  # Public: Moves the cursor to the top of the buffer.
+  moveToTop: ->
+    @setBufferPosition([0,0])
+
+  # Public: Moves the cursor to the bottom of the buffer.
+  moveToBottom: ->
+    @setBufferPosition(@editor.getEofBufferPosition())
+
+  # Public: Moves the cursor to the beginning of the line.
+  moveToBeginningOfScreenLine: ->
+    @setScreenPosition([@getScreenRow(), 0])
+
+  # Public: Moves the cursor to the beginning of the buffer line.
+  moveToBeginningOfLine: ->
+    @setBufferPosition([@getBufferRow(), 0])
+
+  # Public: Moves the cursor to the beginning of the first character in the
+  # line.
+  moveToFirstCharacterOfLine: ->
+    screenRow = @getScreenRow()
+    lineBufferRange = @editor.bufferRangeForScreenRange([[screenRow, 0], [screenRow, Infinity]])
+
+    firstCharacterColumn = null
+    @editor.scanInBufferRange /\S/, lineBufferRange, ({range, stop}) ->
+      firstCharacterColumn = range.start.column
+      stop()
+
+    if firstCharacterColumn? and firstCharacterColumn isnt @getBufferColumn()
+      targetBufferColumn = firstCharacterColumn
+    else
+      targetBufferColumn = lineBufferRange.start.column
+
+    @setBufferPosition([lineBufferRange.start.row, targetBufferColumn])
+
+  # Public: Moves the cursor to the end of the line.
+  moveToEndOfScreenLine: ->
+    @setScreenPosition([@getScreenRow(), Infinity])
+
+  # Public: Moves the cursor to the end of the buffer line.
+  moveToEndOfLine: ->
+    @setBufferPosition([@getBufferRow(), Infinity])
+
+  # Public: Moves the cursor to the beginning of the word.
+  moveToBeginningOfWord: ->
+    @setBufferPosition(@getBeginningOfCurrentWordBufferPosition())
+
+  # Public: Moves the cursor to the end of the word.
+  moveToEndOfWord: ->
+    if position = @getEndOfCurrentWordBufferPosition()
+      @setBufferPosition(position)
+
+  # Public: Moves the cursor to the beginning of the next word.
+  moveToBeginningOfNextWord: ->
+    if position = @getBeginningOfNextWordBufferPosition()
+      @setBufferPosition(position)
+
+  # Public: Moves the cursor to the previous word boundary.
+  moveToPreviousWordBoundary: ->
+    if position = @getPreviousWordBoundaryBufferPosition()
+      @setBufferPosition(position)
+
+  # Public: Moves the cursor to the next word boundary.
+  moveToNextWordBoundary: ->
+    if position = @getMoveNextWordBoundaryBufferPosition()
+      @setBufferPosition(position)
+
+  # Public: Moves the cursor to the beginning of the buffer line, skipping all
+  # whitespace.
+  skipLeadingWhitespace: ->
+    position = @getBufferPosition()
+    scanRange = @getCurrentLineBufferRange()
+    endOfLeadingWhitespace = null
+    @editor.scanInBufferRange /^[ \t]*/, scanRange, ({range}) ->
+      endOfLeadingWhitespace = range.end
+
+    @setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position)
+
+  # Public: Moves the cursor to the beginning of the next paragraph
+  moveToBeginningOfNextParagraph: ->
+    if position = @getBeginningOfNextParagraphBufferPosition()
+      @setBufferPosition(position)
+
+  # Public: Moves the cursor to the beginning of the previous paragraph
+  moveToBeginningOfPreviousParagraph: ->
+    if position = @getBeginningOfPreviousParagraphBufferPosition()
+      @setBufferPosition(position)
+
+  ###
+  Section: Retrieving Positions and Ranges of local boundaries
+  ###
+
+  # Public: Retrieves the buffer position of where the current word starts.
+  #
+  # * `options` (optional) An {Object} with the following keys:
+  #   * `wordRegex` A {RegExp} indicating what constitutes a "word"
+  #     (default: {::wordRegExp}).
+  #   * `includeNonWordCharacters` A {Boolean} indicating whether to include
+  #     non-word characters in the default word regex.
+  #     Has no effect if wordRegex is set.
+  #   * `allowPrevious` A {Boolean} indicating whether the beginning of the
+  #     previous word can be returned.
+  #
+  # Returns a {Range}.
+  getBeginningOfCurrentWordBufferPosition: (options = {}) ->
+    allowPrevious = options.allowPrevious ? true
+    currentBufferPosition = @getBufferPosition()
+    previousNonBlankRow = @editor.buffer.previousNonBlankRow(currentBufferPosition.row) ? 0
+    scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
+
+    beginningOfWordPosition = null
+    @editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
+      if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious
+        beginningOfWordPosition = range.start
+      if not beginningOfWordPosition?.isEqual(currentBufferPosition)
+        stop()
+
+    if beginningOfWordPosition?
+      beginningOfWordPosition
+    else if allowPrevious
+      new Point(0, 0)
+    else
+      currentBufferPosition
+
+  # Public: Retrieves buffer position of previous word boundary. It might be on
+  # the current word, or the previous word.
+  getPreviousWordBoundaryBufferPosition: (options = {}) ->
+    currentBufferPosition = @getBufferPosition()
+    previousNonBlankRow = @editor.buffer.previousNonBlankRow(currentBufferPosition.row)
+    scanRange = [[previousNonBlankRow, 0], currentBufferPosition]
+
+    beginningOfWordPosition = null
+    @editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
+      if range.start.row < currentBufferPosition.row and currentBufferPosition.column > 0
+        # force it to stop at the beginning of each line
+        beginningOfWordPosition = new Point(currentBufferPosition.row, 0)
+      else if range.end.isLessThan(currentBufferPosition)
+        beginningOfWordPosition = range.end
+      else
+        beginningOfWordPosition = range.start
+
+      if not beginningOfWordPosition?.isEqual(currentBufferPosition)
+        stop()
+
+    beginningOfWordPosition or currentBufferPosition
+
+  # Public: Retrieves buffer position of the next word boundary. It might be on
+  # the current word, or the previous word.
+  getMoveNextWordBoundaryBufferPosition: (options = {}) ->
+    currentBufferPosition = @getBufferPosition()
+    scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
+
+    endOfWordPosition = null
+    @editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
+      if range.start.row > currentBufferPosition.row
+        # force it to stop at the beginning of each line
+        endOfWordPosition = new Point(range.start.row, 0)
+      else if range.start.isGreaterThan(currentBufferPosition)
+        endOfWordPosition = range.start
+      else
+        endOfWordPosition = range.end
+
+      if not endOfWordPosition?.isEqual(currentBufferPosition)
+        stop()
+
+    endOfWordPosition or currentBufferPosition
+
+  # Public: Retrieves the buffer position of where the current word ends.
+  #
+  # * `options` (optional) {Object} with the following keys:
+  #   * `wordRegex` A {RegExp} indicating what constitutes a "word"
+  #      (default: {::wordRegExp})
+  #   * `includeNonWordCharacters` A Boolean indicating whether to include
+  #     non-word characters in the default word regex. Has no effect if
+  #     wordRegex is set.
+  #
+  # Returns a {Range}.
+  getEndOfCurrentWordBufferPosition: (options = {}) ->
+    allowNext = options.allowNext ? true
+    currentBufferPosition = @getBufferPosition()
+    scanRange = [currentBufferPosition, @editor.getEofBufferPosition()]
+
+    endOfWordPosition = null
+    @editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) ->
+      if range.start.isLessThanOrEqual(currentBufferPosition) or allowNext
+        endOfWordPosition = range.end
+      if not endOfWordPosition?.isEqual(currentBufferPosition)
+        stop()
+
+    endOfWordPosition ? currentBufferPosition
+
+  # Public: Retrieves the buffer position of where the next word starts.
+  #
+  # * `options` (optional) {Object}
+  #   * `wordRegex` A {RegExp} indicating what constitutes a "word"
+  #     (default: {::wordRegExp}).
+  #
+  # Returns a {Range}
+  getBeginningOfNextWordBufferPosition: (options = {}) ->
+    currentBufferPosition = @getBufferPosition()
+    start = if @isInsideWord() then @getEndOfCurrentWordBufferPosition() else currentBufferPosition
+    scanRange = [start, @editor.getEofBufferPosition()]
+
+    beginningOfNextWordPosition = null
+    @editor.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) ->
+      beginningOfNextWordPosition = range.start
+      stop()
+
+    beginningOfNextWordPosition or currentBufferPosition
+
+  # Public: Returns the buffer Range occupied by the word located under the cursor.
+  #
+  # * `options` (optional) {Object}
+  #   * `wordRegex` A {RegExp} indicating what constitutes a "word"
+  #     (default: {::wordRegExp}).
+  getCurrentWordBufferRange: (options={}) ->
+    startOptions = _.extend(_.clone(options), allowPrevious: false)
+    endOptions = _.extend(_.clone(options), allowNext: false)
+    new Range(@getBeginningOfCurrentWordBufferPosition(startOptions), @getEndOfCurrentWordBufferPosition(endOptions))
+
+  # Public: Returns the buffer Range for the current line.
+  #
+  # * `options` (optional) {Object}
+  #   * `includeNewline` A {Boolean} which controls whether the Range should
+  #     include the newline.
+  getCurrentLineBufferRange: (options) ->
+    @editor.bufferRangeForBufferRow(@getBufferRow(), options)
+
+  # Public: Retrieves the range for the current paragraph.
+  #
+  # A paragraph is defined as a block of text surrounded by empty lines.
+  #
+  # Returns a {Range}.
+  getCurrentParagraphBufferRange: ->
+    @editor.languageMode.rowRangeForParagraphAtBufferRow(@getBufferRow())
+
+  # Public: Returns the characters preceding the cursor in the current word.
+  getCurrentWordPrefix: ->
+    @editor.getTextInBufferRange([@getBeginningOfCurrentWordBufferPosition(), @getBufferPosition()])
+
+  ###
+  Section: Visibility
+  ###
 
   # Public: If the marker range is empty, the cursor is marked as being visible.
   updateVisibility: ->

      @emitter.dispose()
    @needsAutoscroll = true

  ###
  Section: Event Subscription
  ###

  # Essential: Calls your `callback` when the cursor has been moved.
  #
  # * `callback` {Function}
  #   * `event` {Object}

      segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+")
    new RegExp(segments.join("|"), "g")

  ###
  Section: Private
  ###

  changePosition: (options, fn) ->
    @clearSelection()
    @needsAutoscroll = options.autoscroll ? @isLastCursor()
    fn()
    if @needsAutoscroll
      @emit 'autoscrolled' # Support legacy editor
      @autoscroll() if @needsAutoscroll and @editor.manageScrollPosition # Support react editor view

  getPixelRect: ->
    @editor.pixelRectForScreenRange(@getScreenRange())

  getScreenRange: ->
    {row, column} = @getScreenPosition()
    new Range(new Point(row, column), new Point(row, column + 1))

  autoscroll: (options) ->
    @editor.scrollToScreenRange(@getScreenRange(), options)

  getBeginningOfNextParagraphBufferPosition: (editor) ->
    start = @getBufferPosition()
