When trying to compose operators that don't compose, the op stack is cleared

This commit is contained in:
Corey Johnson
2012-02-07 18:01:35 -08:00
parent ddc126734a
commit 6d39306fb2
4 changed files with 53 additions and 17 deletions

View File

@@ -2,7 +2,7 @@ Editor = require 'editor'
VimMode = require 'vim-mode'
describe "VimMode", ->
editor = null
[editor, vimMode] = []
beforeEach ->
editor = new Editor
@@ -36,6 +36,25 @@ describe "VimMode", ->
editor.setCursorPosition([1, 0])
expect(editor.getCursorPosition()).toEqual [1,0]
it "clears the operator stack when commands can't be composed", ->
editor.trigger keydownEvent('d')
expect(vimMode.opStack.length).toBe 1
editor.trigger keydownEvent('x')
expect(vimMode.opStack.length).toBe 0
editor.trigger keydownEvent('d')
expect(vimMode.opStack.length).toBe 1
editor.trigger keydownEvent('\\') # \ is an unused key in vim
expect(vimMode.opStack.length).toBe 0
describe "the esc keybinding", ->
it "clears the operator stack", ->
editor.trigger keydownEvent('d')
expect(vimMode.opStack.length).toBe 1
editor.trigger keydownEvent('esc')
expect(vimMode.opStack.length).toBe 0
describe "the i keybinding", ->
it "puts the editor into insert mode", ->
expect(editor).not.toHaveClass 'insert-mode'

View File

@@ -21,24 +21,26 @@ class VimMode
@setupCommandMode()
setupCommandMode: ->
atom.bindKeys '.command-mode', (e) ->
atom.bindKeys '.command-mode', (e) =>
if e.keystroke.match /^\d$/
return 'command-mode:numeric-prefix'
if e.keystroke.match /^.$/
@resetCommandMode()
return false
@bindCommandModeKeys
'i': 'insert'
'd': 'delete'
'x': 'delete-right'
'h': 'move-left'
'j': 'move-down'
'k': 'move-up'
'l': 'move-right'
'w': 'move-to-next-word'
'b': 'move-to-previous-word'
'left': 'move-left'
'right': 'move-right'
i: 'insert'
d: 'delete'
x: 'delete-right'
h: 'move-left'
j: 'move-down'
k: 'move-up'
l: 'move-right'
w: 'move-to-next-word'
b: 'move-to-previous-word'
esc: 'reset-command-mode'
left: 'move-left'
right: 'move-right'
@handleCommands
'insert': => @activateInsertMode()
@@ -51,6 +53,7 @@ class VimMode
'move-to-next-word': => new motions.MoveToNextWord(@editor)
'move-to-previous-word': => new motions.MoveToPreviousWord(@editor)
'numeric-prefix': (e) => @numericPrefix(e)
'reset-command-mode': => @resetCommandMode()
bindCommandModeKeys: (bindings) ->
prefixedBindings = {}
@@ -78,6 +81,9 @@ class VimMode
@editor.on 'cursor:position-changed', @moveCursorBeforeNewline
resetCommandMode: ->
@opStack = []
moveCursorBeforeNewline: =>
if not @editor.selection.modifyingSelection and @editor.cursor.isOnEOL() and @editor.getCurrentLine().length > 0
@editor.setCursorColumn(@editor.getCurrentLine().length - 1)
@@ -107,10 +113,14 @@ class VimMode
processOpStack: ->
return unless @topOperator().isComplete()
poppedOperator = @opStack.pop()
if @opStack.length
@topOperator().compose(poppedOperator)
@processOpStack()
try
@topOperator().compose(poppedOperator)
@processOpStack()
catch e
(e instanceof operators.OperatorError) and @resetCommandMode() or throw e
else
poppedOperator.execute()

View File

@@ -61,4 +61,4 @@ class MoveToNextWord extends Motion
column = nextLineMatch?.index or 0
{ row, column }
module.exports = { MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord, MoveToPreviousWord }
module.exports = { Motion, MoveLeft, MoveRight, MoveUp, MoveDown, MoveToNextWord, MoveToPreviousWord }

View File

@@ -1,5 +1,9 @@
_ = require 'underscore'
class OperatorError
constructor: (@message) ->
@name = "Operator Error"
class NumericPrefix
count: null
complete: null
@@ -43,8 +47,11 @@ class Delete
@editor.setCursorPosition([@editor.getCursorRow(), 0])
compose: (motion) ->
if not motion.select
throw new OperatorError("Delete must compose with a motion")
@motion = motion
@complete = true
module.exports = { NumericPrefix, Delete }
module.exports = { NumericPrefix, Delete, OperatorError }