Skip to content
This repository was archived by the owner on Apr 6, 2018. It is now read-only.

WIP fix #565 : cursor motion in insert mode should affect . #568

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions keymaps/vim-mode.cson
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
'atom-text-editor.vim-mode.insert-mode':
'ctrl-w': 'editor:delete-to-beginning-of-word'
'ctrl-u': 'editor:delete-to-beginning-of-line'
'left': 'vim-mode:move-left-insert'
'right': 'vim-mode:move-right-insert'

'atom-text-editor.vim-mode.insert-mode:not(.autocomplete-active)':
'up': 'vim-mode:move-up-insert'
'down': 'vim-mode:move-down-insert'

'atom-text-editor.vim-mode:not(.insert-mode)':
'h': 'vim-mode:move-left'
Expand Down
9 changes: 5 additions & 4 deletions lib/motions/general-motions.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Motion
selection.modifySelection => @moveCursor(selection.cursor, count, options)

ensureCursorIsWithinLine: (cursor) ->
return if @vimState.mode is 'visual' or not cursor.selection.isEmpty()
return if @vimState.mode is 'visual' or @vimState.mode is 'insert' or not cursor.selection.isEmpty()
{goalColumn} = cursor
{row, column} = cursor.getBufferPosition()
lastColumn = cursor.getCurrentLineBufferRange().end.column
Expand Down Expand Up @@ -153,9 +153,10 @@ class MoveRight extends Motion
_.times count, =>
wrapToNextLine = settings.wrapLeftRightMotion()

# when the motion is combined with an operator, we will only wrap to the next line
# if we are already at the end of the line (after the last character)
wrapToNextLine = false if @vimState.mode is 'operator-pending' and not cursor.isAtEndOfLine()
# when the motion is in insert mode or is combined with an operator,
# we will only wrap to the next line if we are already
# at the end of the line (after the last character)
wrapToNextLine = false if (@vimState.mode is 'insert' or @vimState.mode is 'operator-pending') and not cursor.isAtEndOfLine()

cursor.moveRight() unless cursor.isAtEndOfLine()
cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine()
Expand Down
10 changes: 10 additions & 0 deletions lib/operators/input.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ class Insert extends Operator

inputOperator: -> true

# an insert operation following cursor motion in insert mode can be cancelled
# and forgotten like it never happened
class InsertCancellable extends Insert

confirmTransaction: (transaction) ->
super
if @typedText?.length is 0
@vimState.history.shift() if @vimState.history[0] is this

class InsertAfter extends Insert
execute: ->
@editor.moveRight() unless @editor.getLastCursor().isAtEndOfLine()
Expand Down Expand Up @@ -189,6 +198,7 @@ module.exports = {
InsertAtBeginningOfLine,
InsertAboveWithNewline,
InsertBelowWithNewline,
InsertCancellable,
Change,
Substitute,
SubstituteLine
Expand Down
15 changes: 15 additions & 0 deletions lib/vim-state.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ class VimState
'move-up': => new Motions.MoveUp(@editor, this)
'move-down': => new Motions.MoveDown(@editor, this)
'move-right': => new Motions.MoveRight(@editor, this)
'move-left-insert': => @interruptInsertMode(); [new Motions.MoveLeft(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-up-insert': => @interruptInsertMode(); [new Motions.MoveUp(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-down-insert': => @interruptInsertMode(); [new Motions.MoveDown(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-right-insert': => @interruptInsertMode(); [new Motions.MoveRight(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-to-next-word': => new Motions.MoveToNextWord(@editor, this)
'move-to-next-whole-word': => new Motions.MoveToNextWholeWord(@editor, this)
'move-to-end-of-word': => new Motions.MoveToEndOfWord(@editor, this)
Expand Down Expand Up @@ -412,6 +416,17 @@ class VimState
for cursor in @editor.getCursors()
cursor.moveLeft() unless cursor.isAtBeginningOfLine()

interruptInsertMode: ->
return unless @mode is 'insert'
@editor.groupChangesSinceCheckpoint(@insertionCheckpoint)
changes = getChangesSinceCheckpoint(@editor.buffer, @insertionCheckpoint)
item = @inputOperator(@history[0])
@insertionCheckpoint = null
if item?
item.confirmChanges(changes)
@setInsertionCheckpoint()


deactivateVisualMode: ->
return unless @mode is 'visual'
for selection in @editor.getSelections()
Expand Down
80 changes: 80 additions & 0 deletions spec/operators-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,74 @@ describe "Operators", ->
keydown '.'
expect(editor.getText()).toBe "abababccc123\nabababccc4567"

it "stores for repeating only the last batch of characters", ->
keydown 'i'
editor.insertText("abc")
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
editor.insertText("de")
keydown 'escape'
expect(editor.getText()).toBe "abdec123\nabdec4567"

keydown '.'
expect(editor.getText()).toBe "abddeec123\nabddeec4567"

describe "without wrapLeftRightMotion", ->
it "handles right motions correctly", ->
editor.setCursorBufferPosition [0, 0]
keydown 'i'
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 3]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 3]
editor.insertText "de"
expect(editor.getText()).toBe "123de\n4567"

it "handles left motions correctly", ->
editor.setCursorBufferPosition [1, 1]
keydown 'i'
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
editor.insertText "de"
expect(editor.getText()).toBe "123\nde4567"

describe "with wrapLeftRightMotion", ->
beforeEach ->
atom.config.set('vim-mode.wrapLeftRightMotion', true)

it "handles right motions correctly", ->
editor.setCursorBufferPosition [0, 0]
keydown 'i'
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 3]
atom.commands.dispatch editorElement, 'vim-mode:move-right-insert'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
editor.insertText "de"
expect(editor.getText()).toBe "123\nde4567"

it "handles left motions correctly", ->
editor.setCursorBufferPosition [1, 2]
keydown 'i'
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [1, 1]
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 3]
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
editor.insertText "de"
expect(editor.getText()).toBe "12de3\n4567"

describe 'the a keybinding', ->
beforeEach ->
editor.setText('')
Expand All @@ -1596,6 +1664,18 @@ describe "Operators", ->
expect(editor.getText()).toBe "abcabc"
expect(editor.getCursorScreenPosition()).toEqual [0, 5]

it "stores for repeating only the last batch of characters, repeats as insert", ->
keydown 'a'
editor.insertText("abc")
atom.commands.dispatch editorElement, 'vim-mode:move-left-insert'
editor.insertText("de")
keydown 'escape'
expect(editor.getText()).toBe "abdec"
expect(editor.getCursorScreenPosition()).toEqual [0, 3]
keydown '.'
expect(editor.getText()).toBe "abddeec"
expect(editor.getCursorScreenPosition()).toEqual [0, 4]

describe "the ctrl-a/ctrl-x keybindings", ->
beforeEach ->
editor.setText('123\nab45\ncd-67ef\nab-5\na-bcdef')
Expand Down