aboutsummaryrefslogtreecommitdiff
path: root/atom/packages/vim-mode/lib/motions
diff options
context:
space:
mode:
authorBen Beltran <ben@nsovocal.com>2015-09-28 12:39:59 -0500
committerBen Beltran <ben@nsovocal.com>2015-09-28 12:39:59 -0500
commit455f099b504ec07dd492ab31987ae05a6f6774c7 (patch)
tree22b0c7fd8e492733b97e661750a2d79c46da451d /atom/packages/vim-mode/lib/motions
parent24c7594d62d8d7fbbcdb64b11ce4adc5d8e6991a (diff)
Adds atom packages
Diffstat (limited to 'atom/packages/vim-mode/lib/motions')
-rw-r--r--atom/packages/vim-mode/lib/motions/find-motion.coffee50
-rw-r--r--atom/packages/vim-mode/lib/motions/general-motions.coffee115
-rw-r--r--atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee2
-rw-r--r--atom/packages/vim-mode/lib/motions/search-motion.coffee14
4 files changed, 112 insertions, 69 deletions
diff --git a/atom/packages/vim-mode/lib/motions/find-motion.coffee b/atom/packages/vim-mode/lib/motions/find-motion.coffee
index 58685d7..2a577a8 100644
--- a/atom/packages/vim-mode/lib/motions/find-motion.coffee
+++ b/atom/packages/vim-mode/lib/motions/find-motion.coffee
@@ -3,14 +3,27 @@
{Point, Range} = require 'atom'
class Find extends MotionWithInput
- constructor: (@editor, @vimState) ->
+ operatesInclusively: true
+
+ constructor: (@editor, @vimState, opts={}) ->
super(@editor, @vimState)
- @vimState.currentFind = this
- @viewModel = new ViewModel(this, class: 'find', singleChar: true, hidden: true)
- @backwards = false
- @repeatReversed = false
@offset = 0
- @repeated = false
+
+ if not opts.repeated
+ @viewModel = new ViewModel(this, class: 'find', singleChar: true, hidden: true)
+ @backwards = false
+ @repeated = false
+ @vimState.globalVimState.currentFind = this
+
+ else
+ @repeated = true
+
+ orig = @vimState.globalVimState.currentFind
+ @backwards = orig.backwards
+ @complete = orig.complete
+ @input = orig.input
+
+ @reverse() if opts.reverse
match: (cursor, count) ->
currentPosition = cursor.getBufferPosition()
@@ -38,17 +51,22 @@ class Find extends MotionWithInput
if (match = @match(cursor, count))?
cursor.setBufferPosition(match)
- repeat: (opts={}) ->
- opts.reverse = !!opts.reverse
- @repeated = true
- if opts.reverse isnt @repeatReversed
- @reverse()
- @repeatReversed = opts.reverse
- this
-
class Till extends Find
- constructor: (@editor, @vimState) ->
- super(@editor, @vimState)
+ constructor: (@editor, @vimState, opts={}) ->
+ super(@editor, @vimState, opts)
@offset = 1
+ match: ->
+ @selectAtLeastOne = false
+ retval = super
+ if retval? and not @backwards
+ @selectAtLeastOne = true
+ retval
+
+ moveSelectionInclusively: (selection, count, options) ->
+ super
+ if selection.isEmpty() and @selectAtLeastOne
+ selection.modifySelection ->
+ selection.cursor.moveRight()
+
module.exports = {Find, Till}
diff --git a/atom/packages/vim-mode/lib/motions/general-motions.coffee b/atom/packages/vim-mode/lib/motions/general-motions.coffee
index 47a3cc7..b5cd627 100644
--- a/atom/packages/vim-mode/lib/motions/general-motions.coffee
+++ b/atom/packages/vim-mode/lib/motions/general-motions.coffee
@@ -11,7 +11,7 @@ class MotionError
@name = 'Motion Error'
class Motion
- operatesInclusively: true
+ operatesInclusively: false
operatesLinewise: false
constructor: (@editor, @vimState) ->
@@ -20,7 +20,9 @@ class Motion
value = for selection in @editor.getSelections()
if @isLinewise()
@moveSelectionLinewise(selection, count, options)
- else if @isInclusive()
+ else if @vimState.mode is 'visual'
+ @moveSelectionVisual(selection, count, options)
+ else if @operatesInclusively
@moveSelectionInclusively(selection, count, options)
else
@moveSelection(selection, count, options)
@@ -61,10 +63,27 @@ class Motion
selection.setBufferRange([[newStartRow, 0], [newEndRow + 1, 0]])
moveSelectionInclusively: (selection, count, options) ->
+ return @moveSelectionVisual(selection, count, options) unless selection.isEmpty()
+
+ selection.modifySelection =>
+ @moveCursor(selection.cursor, count, options)
+ return if selection.isEmpty()
+
+ if selection.isReversed()
+ # for backward motion, add the original starting character of the motion
+ {start, end} = selection.getBufferRange()
+ selection.setBufferRange([start, [end.row, end.column + 1]])
+ else
+ # for forward motion, add the ending character of the motion
+ selection.cursor.moveRight()
+
+ moveSelectionVisual: (selection, count, options) ->
selection.modifySelection =>
range = selection.getBufferRange()
[oldStart, oldEnd] = [range.start, range.end]
+ # in visual mode, atom cursor is after the last selected character,
+ # so here put cursor in the expected place for the following motion
wasEmpty = selection.isEmpty()
wasReversed = selection.isReversed()
unless wasEmpty or wasReversed
@@ -72,6 +91,7 @@ class Motion
@moveCursor(selection.cursor, count, options)
+ # put cursor back after the last character so it is also selected
isEmpty = selection.isEmpty()
isReversed = selection.isReversed()
unless isEmpty or isReversed
@@ -80,23 +100,25 @@ class Motion
range = selection.getBufferRange()
[newStart, newEnd] = [range.start, range.end]
+ # if we reversed or emptied a normal selection
+ # we need to select again the last character deselected above the motion
if (isReversed or isEmpty) and not (wasReversed or wasEmpty)
selection.setBufferRange([newStart, [newEnd.row, oldStart.column + 1]])
+
+ # if we re-reversed a reversed non-empty selection,
+ # we need to keep the last character of the old selection selected
if wasReversed and not wasEmpty and not isReversed
- selection.setBufferRange([[newStart.row, oldEnd.column - 1], newEnd])
+ selection.setBufferRange([[oldEnd.row, oldEnd.column - 1], newEnd])
+
+ # keep a single-character selection non-reversed
+ range = selection.getBufferRange()
+ [newStart, newEnd] = [range.start, range.end]
+ if selection.isReversed() and newStart.row is newEnd.row and newStart.column + 1 is newEnd.column
+ selection.setBufferRange(range, reversed: false)
moveSelection: (selection, count, options) ->
selection.modifySelection => @moveCursor(selection.cursor, count, options)
- ensureCursorIsWithinLine: (cursor) ->
- return if @vimState.mode is 'visual' or not cursor.selection.isEmpty()
- {goalColumn} = cursor
- {row, column} = cursor.getBufferPosition()
- lastColumn = cursor.getCurrentLineBufferRange().end.column
- if column >= lastColumn - 1
- cursor.setBufferPosition([row, Math.max(lastColumn - 1, 0)])
- cursor.goalColumn ?= goalColumn
-
isComplete: -> true
isRecordable: -> false
@@ -107,21 +129,41 @@ class Motion
else
@operatesLinewise
- isInclusive: ->
- @vimState.mode is 'visual' or @operatesInclusively
-
class CurrentSelection extends Motion
constructor: (@editor, @vimState) ->
super(@editor, @vimState)
- @selection = @editor.getSelectedBufferRanges()
+ @lastSelectionRange = @editor.getSelectedBufferRange()
+ @wasLinewise = @isLinewise()
execute: (count=1) ->
_.times(count, -> true)
select: (count=1) ->
- @editor.setSelectedBufferRanges(@selection)
+ # in visual mode, the current selections are already there
+ # if we're not in visual mode, we are repeating some operation and need to re-do the selections
+ unless @vimState.mode is 'visual'
+ if @wasLinewise
+ @selectLines()
+ else
+ @selectCharacters()
+
_.times(count, -> true)
+ selectLines: ->
+ lastSelectionExtent = @lastSelectionRange.getExtent()
+ for selection in @editor.getSelections()
+ cursor = selection.cursor.getBufferPosition()
+ selection.setBufferRange [[cursor.row, 0], [cursor.row + lastSelectionExtent.row, 0]]
+ return
+
+ selectCharacters: ->
+ lastSelectionExtent = @lastSelectionRange.getExtent()
+ for selection in @editor.getSelections()
+ {start} = selection.getBufferRange()
+ newEnd = start.traverse(lastSelectionExtent)
+ selection.setBufferRange([start, newEnd])
+ return
+
# Public: Generic class for motions that require extra input
class MotionWithInput extends Motion
constructor: (@editor, @vimState) ->
@@ -139,16 +181,11 @@ class MotionWithInput extends Motion
@complete = true
class MoveLeft extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
- _.times count, =>
+ _.times count, ->
cursor.moveLeft() if not cursor.isAtBeginningOfLine() or settings.wrapLeftRightMotion()
- @ensureCursorIsWithinLine(cursor)
class MoveRight extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, =>
wrapToNextLine = settings.wrapLeftRightMotion()
@@ -159,16 +196,14 @@ class MoveRight extends Motion
cursor.moveRight() unless cursor.isAtEndOfLine()
cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine()
- @ensureCursorIsWithinLine(cursor)
class MoveUp extends Motion
operatesLinewise: true
moveCursor: (cursor, count=1) ->
- _.times count, =>
+ _.times count, ->
unless cursor.getScreenRow() is 0
cursor.moveUp()
- @ensureCursorIsWithinLine(cursor)
class MoveDown extends Motion
operatesLinewise: true
@@ -177,18 +212,13 @@ class MoveDown extends Motion
_.times count, =>
unless cursor.getScreenRow() is @editor.getLastScreenRow()
cursor.moveDown()
- @ensureCursorIsWithinLine(cursor)
class MoveToPreviousWord extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, ->
cursor.moveToBeginningOfWord()
class MoveToPreviousWholeWord extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, =>
cursor.moveToBeginningOfWord()
@@ -205,7 +235,6 @@ class MoveToPreviousWholeWord extends Motion
class MoveToNextWord extends Motion
wordRegex: null
- operatesInclusively: false
moveCursor: (cursor, count=1, options) ->
_.times count, =>
@@ -236,6 +265,7 @@ class MoveToNextWholeWord extends MoveToNextWord
wordRegex: WholeWordOrEmptyLineRegex
class MoveToEndOfWord extends Motion
+ operatesInclusively: true
wordRegex: null
moveCursor: (cursor, count=1) ->
@@ -260,8 +290,6 @@ class MoveToEndOfWholeWord extends MoveToEndOfWord
wordRegex: WholeWordRegex
class MoveToNextParagraph extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, ->
cursor.moveToBeginningOfNextParagraph()
@@ -284,8 +312,6 @@ class MoveToAbsoluteLine extends MoveToLine
cursor.moveToEndOfLine() if cursor.getBufferColumn() is 0
class MoveToRelativeLine extends MoveToLine
- operatesLinewise: true
-
moveCursor: (cursor, count=1) ->
{row, column} = cursor.getBufferPosition()
cursor.setBufferPosition([row + (count - 1), 0])
@@ -300,15 +326,11 @@ class MoveToScreenLine extends MoveToLine
cursor.setScreenPosition([@getDestinationRow(count), 0])
class MoveToBeginningOfLine extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, ->
cursor.moveToBeginningOfLine()
class MoveToFirstCharacterOfLine extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
_.times count, ->
cursor.moveToBeginningOfLine()
@@ -316,22 +338,18 @@ class MoveToFirstCharacterOfLine extends Motion
class MoveToFirstCharacterOfLineAndDown extends Motion
operatesLinewise: true
- operatesInclusively: true
- moveCursor: (cursor, count=0) ->
+ moveCursor: (cursor, count=1) ->
_.times count-1, ->
cursor.moveDown()
cursor.moveToBeginningOfLine()
cursor.moveToFirstCharacterOfLine()
class MoveToLastCharacterOfLine extends Motion
- operatesInclusively: false
-
moveCursor: (cursor, count=1) ->
- _.times count, =>
+ _.times count, ->
cursor.moveToEndOfLine()
cursor.goalColumn = Infinity
- @ensureCursorIsWithinLine(cursor)
class MoveToLastNonblankCharacterOfLineAndDown extends Motion
operatesInclusively: true
@@ -354,7 +372,6 @@ class MoveToLastNonblankCharacterOfLineAndDown extends Motion
class MoveToFirstCharacterOfLineUp extends Motion
operatesLinewise: true
- operatesInclusively: true
moveCursor: (cursor, count=1) ->
_.times count, ->
@@ -398,7 +415,7 @@ class MoveToBottomOfScreen extends MoveToScreenLine
lastScreenRow - offset
class MoveToMiddleOfScreen extends MoveToScreenLine
- getDestinationRow: (count) ->
+ getDestinationRow: ->
firstScreenRow = @editorElement.getFirstVisibleScreenRow()
lastScreenRow = @editorElement.getLastVisibleScreenRow()
height = lastScreenRow - firstScreenRow
@@ -428,7 +445,7 @@ class ScrollKeepingCursor extends MoveToLine
{row, column} = @editor.getCursorScreenPosition()
@currentFirstScreenRow - @previousFirstScreenRow + row
- scrollScreen: (count = 1) ->
+ scrollScreen: (count=1) ->
@previousFirstScreenRow = @editorElement.getFirstVisibleScreenRow()
destination = @scrollDestination(count)
@editor.setScrollTop(destination)
diff --git a/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee b/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee
index 0187620..3603e1e 100644
--- a/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee
+++ b/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee
@@ -4,8 +4,6 @@
module.exports =
class MoveToMark extends MotionWithInput
- operatesInclusively: false
-
constructor: (@editor, @vimState, @linewise=true) ->
super(@editor, @vimState)
@operatesLinewise = @linewise
diff --git a/atom/packages/vim-mode/lib/motions/search-motion.coffee b/atom/packages/vim-mode/lib/motions/search-motion.coffee
index 11761ad..fa65e19 100644
--- a/atom/packages/vim-mode/lib/motions/search-motion.coffee
+++ b/atom/packages/vim-mode/lib/motions/search-motion.coffee
@@ -6,8 +6,6 @@ SearchViewModel = require '../view-models/search-view-model'
settings = require '../settings'
class SearchBase extends MotionWithInput
- operatesInclusively: false
-
constructor: (@editor, @vimState, options = {}) ->
super(@editor, @vimState)
@reverse = @initiallyReversed = false
@@ -27,6 +25,8 @@ class SearchBase extends MotionWithInput
atom.beep()
scan: (cursor) ->
+ return [] if @input.characters is ""
+
currentPosition = cursor.getBufferPosition()
[rangesBefore, rangesAfter] = [[], []]
@@ -75,6 +75,16 @@ class Search extends SearchBase
constructor: (@editor, @vimState) ->
super(@editor, @vimState)
@viewModel = new SearchViewModel(this)
+ @updateViewModel()
+
+ reversed: =>
+ @initiallyReversed = @reverse = true
+ @updateCurrentSearch()
+ @updateViewModel()
+ this
+
+ updateViewModel: ->
+ @viewModel.update(@initiallyReversed)
class SearchCurrentWord extends SearchBase
@keywordRegex: null