]> git.r.bdr.sh - rbdr/dotfiles/blobdiff - atom/packages/vim-mode/lib/motions/general-motions.coffee
Update vim plugins
[rbdr/dotfiles] / atom / packages / vim-mode / lib / motions / general-motions.coffee
index 47a3cc78df708ab5b9cf6fdf69f08a3a76028bb7..b5cd627225ca832f6ca25a6c182b09c868c27132 100644 (file)
@@ -11,7 +11,7 @@ class MotionError
     @name = 'Motion Error'
 
 class Motion
     @name = 'Motion Error'
 
 class Motion
-  operatesInclusively: true
+  operatesInclusively: false
   operatesLinewise: false
 
   constructor: (@editor, @vimState) ->
   operatesLinewise: false
 
   constructor: (@editor, @vimState) ->
@@ -20,7 +20,9 @@ class Motion
     value = for selection in @editor.getSelections()
       if @isLinewise()
         @moveSelectionLinewise(selection, count, options)
     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)
         @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) ->
       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]
 
     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
       wasEmpty = selection.isEmpty()
       wasReversed = selection.isReversed()
       unless wasEmpty or wasReversed
@@ -72,6 +91,7 @@ class Motion
 
       @moveCursor(selection.cursor, count, options)
 
 
       @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
       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]
 
       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 (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
       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)
 
 
   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
   isComplete: -> true
 
   isRecordable: -> false
@@ -107,21 +129,41 @@ class Motion
     else
       @operatesLinewise
 
     else
       @operatesLinewise
 
-  isInclusive: ->
-    @vimState.mode is 'visual' or @operatesInclusively
-
 class CurrentSelection extends Motion
   constructor: (@editor, @vimState) ->
     super(@editor, @vimState)
 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) ->
 
   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)
 
     _.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) ->
 # 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
     @complete = true
 
 class MoveLeft extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
   moveCursor: (cursor, count=1) ->
-    _.times count, =>
+    _.times count, ->
       cursor.moveLeft() if not cursor.isAtBeginningOfLine() or settings.wrapLeftRightMotion()
       cursor.moveLeft() if not cursor.isAtBeginningOfLine() or settings.wrapLeftRightMotion()
-      @ensureCursorIsWithinLine(cursor)
 
 class MoveRight extends Motion
 
 class MoveRight extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, =>
       wrapToNextLine = settings.wrapLeftRightMotion()
   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()
 
       cursor.moveRight() unless cursor.isAtEndOfLine()
       cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine()
-      @ensureCursorIsWithinLine(cursor)
 
 class MoveUp extends Motion
   operatesLinewise: true
 
   moveCursor: (cursor, count=1) ->
 
 class MoveUp extends Motion
   operatesLinewise: true
 
   moveCursor: (cursor, count=1) ->
-    _.times count, =>
+    _.times count, ->
       unless cursor.getScreenRow() is 0
         cursor.moveUp()
       unless cursor.getScreenRow() is 0
         cursor.moveUp()
-        @ensureCursorIsWithinLine(cursor)
 
 class MoveDown extends Motion
   operatesLinewise: true
 
 class MoveDown extends Motion
   operatesLinewise: true
@@ -177,18 +212,13 @@ class MoveDown extends Motion
     _.times count, =>
       unless cursor.getScreenRow() is @editor.getLastScreenRow()
         cursor.moveDown()
     _.times count, =>
       unless cursor.getScreenRow() is @editor.getLastScreenRow()
         cursor.moveDown()
-        @ensureCursorIsWithinLine(cursor)
 
 class MoveToPreviousWord extends Motion
 
 class MoveToPreviousWord extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfWord()
 
 class MoveToPreviousWholeWord extends Motion
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfWord()
 
 class MoveToPreviousWholeWord extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, =>
       cursor.moveToBeginningOfWord()
   moveCursor: (cursor, count=1) ->
     _.times count, =>
       cursor.moveToBeginningOfWord()
@@ -205,7 +235,6 @@ class MoveToPreviousWholeWord extends Motion
 
 class MoveToNextWord extends Motion
   wordRegex: null
 
 class MoveToNextWord extends Motion
   wordRegex: null
-  operatesInclusively: false
 
   moveCursor: (cursor, count=1, options) ->
     _.times count, =>
 
   moveCursor: (cursor, count=1, options) ->
     _.times count, =>
@@ -236,6 +265,7 @@ class MoveToNextWholeWord extends MoveToNextWord
   wordRegex: WholeWordOrEmptyLineRegex
 
 class MoveToEndOfWord extends Motion
   wordRegex: WholeWordOrEmptyLineRegex
 
 class MoveToEndOfWord extends Motion
+  operatesInclusively: true
   wordRegex: null
 
   moveCursor: (cursor, count=1) ->
   wordRegex: null
 
   moveCursor: (cursor, count=1) ->
@@ -260,8 +290,6 @@ class MoveToEndOfWholeWord extends MoveToEndOfWord
   wordRegex: WholeWordRegex
 
 class MoveToNextParagraph extends Motion
   wordRegex: WholeWordRegex
 
 class MoveToNextParagraph extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfNextParagraph()
   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
     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])
   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
     cursor.setScreenPosition([@getDestinationRow(count), 0])
 
 class MoveToBeginningOfLine extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfLine()
 
 class MoveToFirstCharacterOfLine extends Motion
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfLine()
 
 class MoveToFirstCharacterOfLine extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfLine()
   moveCursor: (cursor, count=1) ->
     _.times count, ->
       cursor.moveToBeginningOfLine()
@@ -316,22 +338,18 @@ class MoveToFirstCharacterOfLine extends Motion
 
 class MoveToFirstCharacterOfLineAndDown extends Motion
   operatesLinewise: true
 
 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
     _.times count-1, ->
       cursor.moveDown()
     cursor.moveToBeginningOfLine()
     cursor.moveToFirstCharacterOfLine()
 
 class MoveToLastCharacterOfLine extends Motion
-  operatesInclusively: false
-
   moveCursor: (cursor, count=1) ->
   moveCursor: (cursor, count=1) ->
-    _.times count, =>
+    _.times count, ->
       cursor.moveToEndOfLine()
       cursor.goalColumn = Infinity
       cursor.moveToEndOfLine()
       cursor.goalColumn = Infinity
-      @ensureCursorIsWithinLine(cursor)
 
 class MoveToLastNonblankCharacterOfLineAndDown extends Motion
   operatesInclusively: true
 
 class MoveToLastNonblankCharacterOfLineAndDown extends Motion
   operatesInclusively: true
@@ -354,7 +372,6 @@ class MoveToLastNonblankCharacterOfLineAndDown extends Motion
 
 class MoveToFirstCharacterOfLineUp extends Motion
   operatesLinewise: true
 
 class MoveToFirstCharacterOfLineUp extends Motion
   operatesLinewise: true
-  operatesInclusively: true
 
   moveCursor: (cursor, count=1) ->
     _.times count, ->
 
   moveCursor: (cursor, count=1) ->
     _.times count, ->
@@ -398,7 +415,7 @@ class MoveToBottomOfScreen extends MoveToScreenLine
     lastScreenRow - offset
 
 class MoveToMiddleOfScreen extends MoveToScreenLine
     lastScreenRow - offset
 
 class MoveToMiddleOfScreen extends MoveToScreenLine
-  getDestinationRow: (count) ->
+  getDestinationRow: ->
     firstScreenRow = @editorElement.getFirstVisibleScreenRow()
     lastScreenRow = @editorElement.getLastVisibleScreenRow()
     height = lastScreenRow - firstScreenRow
     firstScreenRow = @editorElement.getFirstVisibleScreenRow()
     lastScreenRow = @editorElement.getLastVisibleScreenRow()
     height = lastScreenRow - firstScreenRow
@@ -428,7 +445,7 @@ class ScrollKeepingCursor extends MoveToLine
     {row, column} = @editor.getCursorScreenPosition()
     @currentFirstScreenRow - @previousFirstScreenRow + row
 
     {row, column} = @editor.getCursorScreenPosition()
     @currentFirstScreenRow - @previousFirstScreenRow + row
 
-  scrollScreen: (count = 1) ->
+  scrollScreen: (count=1) ->
     @previousFirstScreenRow = @editorElement.getFirstVisibleScreenRow()
     destination = @scrollDestination(count)
     @editor.setScrollTop(destination)
     @previousFirstScreenRow = @editorElement.getFirstVisibleScreenRow()
     destination = @scrollDestination(count)
     @editor.setScrollTop(destination)