Merge branch 'master' of github.com:probablycorey/Atomicity

This commit is contained in:
Nathan Sobo
2012-01-13 13:05:14 -08:00
7 changed files with 141 additions and 62 deletions

View File

@@ -119,53 +119,66 @@ describe "GlobalKeymap", ->
keymap.handleKeyEvent(keypressEvent('y', target: target))
expect(bazHandler).toHaveBeenCalled()
describe ".bindAllKeys(fn)", ->
it "calls given fn when selector matches", ->
handler = jasmine.createSpy 'handler'
keymap.bindKeys '.child-node', handler
describe ".bindKeys(selector, fnOrMap)", ->
describe "when called with a function", ->
it "calls the given function when selector matches", ->
handler = jasmine.createSpy 'handler'
keymap.bindKeys '.child-node', handler
target = fragment.find('.grandchild-node')[0]
event = keypressEvent('y', target: target)
keymap.handleKeyEvent event
target = fragment.find('.grandchild-node')[0]
event = keypressEvent('y', target: target)
keymap.handleKeyEvent event
expect(handler).toHaveBeenCalledWith(event)
expect(handler).toHaveBeenCalledWith(event)
describe "when the handler function returns a command string", ->
it "triggers the command event on the target and stops propagating the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> 'bar'
fooHandler = jasmine.createSpy('fooHandler')
barHandler = jasmine.createSpy('barHandler')
fragment.on 'foo', fooHandler
fragment.on 'bar', barHandler
describe "when the function returns a command string", ->
it "triggers the command event on the target and stops propagating the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> 'bar'
fooHandler = jasmine.createSpy('fooHandler')
barHandler = jasmine.createSpy('barHandler')
fragment.on 'foo', fooHandler
fragment.on 'bar', barHandler
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
expect(fooHandler).not.toHaveBeenCalled()
expect(barHandler).toHaveBeenCalled()
expect(fooHandler).not.toHaveBeenCalled()
expect(barHandler).toHaveBeenCalled()
describe "when the handler function returns false", ->
it "stops propagating the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> false
fooHandler = jasmine.createSpy('fooHandler')
fragment.on 'foo', fooHandler
describe "when the function returns false", ->
it "stops propagating the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> false
fooHandler = jasmine.createSpy('fooHandler')
fragment.on 'foo', fooHandler
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
expect(fooHandler).not.toHaveBeenCalled()
expect(fooHandler).not.toHaveBeenCalled()
describe "when the handler function returns anything other than a string or false", ->
it "continues to propagate the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> undefined
fooHandler = jasmine.createSpy('fooHandler')
fragment.on 'foo', fooHandler
describe "when the function returns anything other than a string or false", ->
it "continues to propagate the event", ->
keymap.bindKeys '*', 'x': 'foo'
keymap.bindKeys '*', -> undefined
fooHandler = jasmine.createSpy('fooHandler')
fragment.on 'foo', fooHandler
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('x', target: target))
expect(fooHandler).toHaveBeenCalled()
expect(fooHandler).toHaveBeenCalled()
describe ".bindKey(selector, pattern, eventName)", ->
it "binds a single key", ->
keymap.bindKey '.child-node', 'z', 'foo'
fooHandler = jasmine.createSpy('fooHandler')
fragment.on 'foo', fooHandler
target = fragment.find('.child-node')[0]
keymap.handleKeyEvent(keydownEvent('z', target: target))
expect(fooHandler).toHaveBeenCalled()

View File

@@ -39,6 +39,25 @@ describe "VimMode", ->
expect(editor.buffer.getText()).toBe '1345'
expect(editor.getCursor()).toEqual(column: 1, row: 0)
describe "basic motion bindings", ->
beforeEach ->
editor.buffer.setText("12345\nabcde\nABCDE")
editor.setCursor(column: 1, row: 1)
describe "the h keybinding", ->
it "move the cursor left", ->
editor.trigger keydownEvent('h')
expect(editor.getCursor()).toEqual(column: 0, row: 1)
editor.trigger keydownEvent('h')
expect(editor.getCursor()).toEqual(column: 0, row: 1)
describe "the j keybinding", ->
it "move the cursor up", ->
editor.trigger keydownEvent('j')
expect(editor.getCursor()).toEqual(column: 1, row: 0)
editor.trigger keydownEvent('j')
expect(editor.getCursor()).toEqual(column: 1, row: 0)
describe "numeric prefix binding", ->
it "repeats the following operation N times", ->
editor.buffer.setText("12345")

View File

@@ -15,6 +15,9 @@ class App
bindKeys: (selector, bindings) ->
@globalKeymap.bindKeys(selector, bindings)
bindKey: (selector, pattern, eventName) ->
@globalKeymap.bindKey(selector, pattern, eventName)
open: (url) ->
OSX.NSApp.open url

View File

@@ -64,5 +64,8 @@ class Editor extends Template
deleteChar: ->
@aceEditor.remove 'right'
moveLeft: ->
@aceEditor.navigateLeft()
moveUp: ->
@aceEditor.navigateUp()

View File

@@ -12,6 +12,11 @@ class GlobalKeymap
bindKeys: (selector, bindings) ->
@bindingSets.unshift(new BindingSet(selector, bindings))
bindKey: (selector, pattern, eventName) ->
bindings = {}
bindings[pattern] = eventName
@bindKeys(selector, bindings)
handleKeyEvent: (event) ->
currentNode = $(event.target)
while currentNode.length

View File

@@ -23,3 +23,17 @@ module.exports =
isComplete: -> true
MoveLeft: class
execute: (editor) ->
{column, row} = editor.getCursor()
editor.moveLeft() if column > 0
isComplete: -> true
MoveUp: class
execute: (editor) ->
{column, row} = editor.getCursor()
editor.moveUp() if row > 0
isComplete: -> true

View File

@@ -1,6 +1,6 @@
_ = require 'underscore'
$ = require 'jquery'
{ NumericPrefix, DeleteChar } = require 'vim-mode-operators'
op = require 'vim-mode-operators'
module.exports =
class VimMode
@@ -9,16 +9,52 @@ class VimMode
constructor: (@editor) ->
@opStack = []
atom.bindKeys '.command-mode', -> false
atom.bindKeys '.command-mode', @commandModeBindings()
atom.bindKeys '.insert-mode', '<esc>': 'command-mode:activate'
@editor.addClass('command-mode')
@editor.on 'insert-mode:activate', => @activateInsertMode()
@editor.on 'command-mode:activate', => @activateCommandMode()
@editor.on 'command-mode:delete-char', => @deleteChar()
@editor.on 'command-mode:numeric-prefix', (e) => @numericPrefix(e)
atom.bindKeys '.editor', '<esc>': 'activate-command-mode'
@editor.on 'activate-command-mode', => @activateCommandMode()
@setupCommandMode()
setupCommandMode: ->
atom.bindKeys '.command-mode', -> false
@bindCommandModeKeys
'i': 'insert'
'x': 'delete-char'
'h': 'move-left'
'j': 'move-up'
@handleCommands
'insert': => @activateInsertMode()
'delete-char': => new op.DeleteChar
'move-left': => new op.MoveLeft
'move-up': => new op.MoveUp
for i in [0..9]
do (i) =>
@registerCommand i, "numeric-prefix-#{i}", => new op.NumericPrefix(i)
bindCommandModeKeys: (bindings) ->
prefixedBindings = {}
for pattern, commandName of bindings
prefixedBindings[pattern] = "command-mode:#{commandName}"
atom.bindKeys ".command-mode", prefixedBindings
handleCommands: (commands) ->
_.each commands, (fn, commandName) =>
eventName = "command-mode:#{commandName}"
@editor.on eventName, =>
possibleOperator = fn()
@pushOperator(possibleOperator) if possibleOperator.execute?
registerCommand: (binding, commandName, fn)->
eventName = "command-mode:#{commandName}"
atom.bindKey '.command-mode', binding, eventName
@editor.on eventName, =>
possibleOperator = fn()
@pushOperator(possibleOperator) if possibleOperator.execute?
activateInsertMode: ->
@editor.removeClass('command-mode')
@@ -28,20 +64,6 @@ class VimMode
@editor.removeClass('insert-mode')
@editor.addClass('command-mode')
deleteChar: ->
@pushOperator(new DeleteChar)
numericPrefix: (e) ->
@pushOperator(new NumericPrefix(e.keyEvent.char))
commandModeBindings: ->
bindings =
'i': 'insert-mode:activate'
'x': 'command-mode:delete-char'
for i in [0..9]
bindings[i] = 'command-mode:numeric-prefix'
bindings
pushOperator: (op) ->
@opStack.push(op)
@processOpStack()