Add subword navigation

- Add commands for moving, selecting, and deleting camelCase words
This commit is contained in:
Darrell Sandstrom
2015-03-01 17:17:17 -08:00
parent 115f519d6a
commit a8c4943d91
5 changed files with 368 additions and 0 deletions

View File

@@ -407,6 +407,21 @@ class Cursor extends Model
if position = @getNextWordBoundaryBufferPosition()
@setBufferPosition(position)
# Public: Moves the cursor to the previous subword boundary.
moveToPreviousSubwordBoundary: ->
options = {wordRegex: @subwordRegExp(backwards: true)}
if position = @getPreviousWordBoundaryBufferPosition(options)
# HACK: to fix going left on first line
if position.isEqual(@getBufferPosition())
position = new Point(position.row, 0)
@setBufferPosition(position)
# Public: Moves the cursor to the next subword boundary.
moveToNextSubwordBoundary: ->
options = {wordRegex: @subwordRegExp()}
if position = @getNextWordBoundaryBufferPosition(options)
@setBufferPosition(position)
# Public: Moves the cursor to the beginning of the buffer line, skipping all
# whitespace.
skipLeadingWhitespace: ->
@@ -650,6 +665,25 @@ class Cursor extends Model
segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+")
new RegExp(segments.join("|"), "g")
# Public: Get the RegExp used by the cursor to determine what a "subword" is.
#
# * `options` (optional) {Object} with the following keys:
# * `backwards` A {Boolean} indicating whether to look forwards or backwards
# for the next subword. (default: false)
#
# Returns a {RegExp}.
subwordRegExp: (options={}) ->
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
segments = ["^[\t ]*$"]
segments.push("[A-Z]?[a-z]+")
segments.push("[A-Z]+(?![a-z])")
segments.push("\\d+")
if options.backwards
segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+\\s*")
else
segments.push("\\s*[#{_.escapeRegExp(nonWordCharacters)}]+")
new RegExp(segments.join("|"), "g")
###
Section: Private
###

View File

@@ -291,6 +291,14 @@ class Selection extends Model
selectToNextWordBoundary: ->
@modifySelection => @cursor.moveToNextWordBoundary()
# Public: Selects text to the previous subword boundary.
selectToPreviousSubwordBoundary: ->
@modifySelection => @cursor.moveToPreviousSubwordBoundary()
# Public: Selects text to the next subword boundary.
selectToNextSubwordBoundary: ->
@modifySelection => @cursor.moveToNextSubwordBoundary()
# Public: Selects all the text from the current cursor position to the
# beginning of the next paragraph.
selectToBeginningOfNextParagraph: ->
@@ -454,6 +462,18 @@ class Selection extends Model
@selectToEndOfWord() if @isEmpty()
@deleteSelectedText()
# Public: Removes the selection or all characters from the start of the
# selection to the end of the current word if nothing is selected.
deleteToBeginningOfSubword: ->
@selectToPreviousSubwordBoundary() if @isEmpty()
@deleteSelectedText()
# Public: Removes the selection or all characters from the start of the
# selection to the end of the current word if nothing is selected.
deleteToEndOfSubword: ->
@selectToNextSubwordBoundary() if @isEmpty()
@deleteSelectedText()
# Public: Removes only the selected text.
deleteSelectedText: ->
bufferRange = @getBufferRange()

View File

@@ -259,6 +259,8 @@ atom.commands.add 'atom-text-editor', stopEventPropagation(
'editor:move-to-beginning-of-next-word': -> @moveToBeginningOfNextWord()
'editor:move-to-previous-word-boundary': -> @moveToPreviousWordBoundary()
'editor:move-to-next-word-boundary': -> @moveToNextWordBoundary()
'editor:move-to-previous-subword-boundary': -> @moveToPreviousSubwordBoundary()
'editor:move-to-next-subword-boundary': -> @moveToNextSubwordBoundary()
'editor:select-to-beginning-of-next-paragraph': -> @selectToBeginningOfNextParagraph()
'editor:select-to-beginning-of-previous-paragraph': -> @selectToBeginningOfPreviousParagraph()
'editor:select-to-end-of-line': -> @selectToEndOfLine()
@@ -268,6 +270,8 @@ atom.commands.add 'atom-text-editor', stopEventPropagation(
'editor:select-to-beginning-of-next-word': -> @selectToBeginningOfNextWord()
'editor:select-to-next-word-boundary': -> @selectToNextWordBoundary()
'editor:select-to-previous-word-boundary': -> @selectToPreviousWordBoundary()
'editor:select-to-next-subword-boundary': -> @selectToNextSubwordBoundary()
'editor:select-to-previous-subword-boundary': -> @selectToPreviousSubwordBoundary()
'editor:select-to-first-character-of-line': -> @selectToFirstCharacterOfLine()
'editor:select-line': -> @selectLinesContainingCursors()
)
@@ -282,6 +286,8 @@ atom.commands.add 'atom-text-editor', stopEventPropagationAndGroupUndo(
'editor:delete-to-beginning-of-line': -> @deleteToBeginningOfLine()
'editor:delete-to-end-of-line': -> @deleteToEndOfLine()
'editor:delete-to-end-of-word': -> @deleteToEndOfWord()
'editor:delete-to-beginning-of-subword': -> @deleteToBeginningOfSubword()
'editor:delete-to-end-of-subword': -> @deleteToEndOfSubword()
'editor:delete-line': -> @deleteLine()
'editor:cut-to-end-of-line': -> @cutToEndOfLine()
'editor:transpose': -> @transpose()

View File

@@ -1083,6 +1083,18 @@ class TextEditor extends Model
deleteToBeginningOfWord: ->
@mutateSelectedText (selection) -> selection.deleteToBeginningOfWord()
# Extended: For each selection, if the selection is empty, delete all characters
# of the containing subword following the cursor. Otherwise delete the selected
# text.
deleteToBeginningOfSubword: ->
@mutateSelectedText (selection) -> selection.deleteToBeginningOfSubword()
# Extended: For each selection, if the selection is empty, delete all characters
# of the containing subword following the cursor. Otherwise delete the selected
# text.
deleteToEndOfSubword: ->
@mutateSelectedText (selection) -> selection.deleteToEndOfSubword()
# Extended: For each selection, if the selection is empty, delete all characters
# of the containing line that precede the cursor. Otherwise delete the
# selected text.
@@ -1733,6 +1745,14 @@ class TextEditor extends Model
deprecate("Use TextEditor::moveToNextWordBoundary() instead")
@moveToNextWordBoundary()
# Extended: Move every cursor to the previous subword boundary.
moveToPreviousSubwordBoundary: ->
@moveCursors (cursor) -> cursor.moveToPreviousSubwordBoundary()
# Extended: Move every cursor to the next subword boundary.
moveToNextSubwordBoundary: ->
@moveCursors (cursor) -> cursor.moveToNextSubwordBoundary()
# Extended: Move every cursor to the beginning of the next paragraph.
moveToBeginningOfNextParagraph: ->
@moveCursors (cursor) -> cursor.moveToBeginningOfNextParagraph()
@@ -2061,6 +2081,20 @@ class TextEditor extends Model
selectToEndOfWord: ->
@expandSelectionsForward (selection) -> selection.selectToEndOfWord()
# Extended: For each selection, move its cursor to the preceding subword
# boundary while maintaining the selection's tail position.
#
# This method may merge selections that end up intersecting.
selectToPreviousSubwordBoundary: ->
@expandSelectionsBackward (selection) -> selection.selectToPreviousSubwordBoundary()
# Extended: For each selection, move its cursor to the next subword boundary
# while maintaining the selection's tail position.
#
# This method may merge selections that end up intersecting.
selectToNextSubwordBoundary: ->
@expandSelectionsForward (selection) -> selection.selectToNextSubwordBoundary()
# Essential: For each cursor, select the containing line.
#
# This method merges selections on successive lines.