Merge branch 'master' into structural-folding

This commit is contained in:
Corey Johnson
2012-05-31 16:24:01 -07:00
13 changed files with 147 additions and 53 deletions

View File

@@ -190,18 +190,6 @@ describe "Keymap", ->
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()
describe ".keystrokeStringForEvent(event)", ->
describe "when no modifiers are pressed", ->
it "returns a string that identifies the key pressed", ->
@@ -224,3 +212,24 @@ describe "Keymap", ->
expect(keymap.keystrokeStringForEvent(keydownEvent('{', shiftKey: true))).toBe '{'
expect(keymap.keystrokeStringForEvent(keydownEvent('left', shiftKey: true))).toBe 'shift-left'
expect(keymap.keystrokeStringForEvent(keydownEvent('Left', shiftKey: true))).toBe 'shift-left'
describe ".bindingsForElement(element)", ->
it "returns the matching bindings for the element", ->
keymap.bindKeys '.command-mode', 'c': 'c'
keymap.bindKeys '.grandchild-node', 'g': 'g'
bindings = keymap.bindingsForElement(fragment.find('.grandchild-node'))
expect(Object.keys(bindings).length).toBe 2
expect(bindings['c']).toEqual "c"
expect(bindings['g']).toEqual "g"
describe "when multiple bindings match a keystroke", ->
it "only returns bindings that match the most specific selector", ->
keymap.bindKeys '.command-mode', 'g': 'command-mode'
keymap.bindKeys '.command-mode .grandchild-node', 'g': 'command-and-grandchild-node'
keymap.bindKeys '.grandchild-node', 'g': 'grandchild-node'
bindings = keymap.bindingsForElement(fragment.find('.grandchild-node'))
expect(Object.keys(bindings).length).toBe 1
expect(bindings['g']).toEqual "command-and-grandchild-node"

View File

@@ -356,6 +356,32 @@ describe "RootView", ->
rootView.trigger(event)
expect(commandHandler).toHaveBeenCalled()
describe ".activeKeybindings()", ->
originalKeymap = null
keymap = null
editor = null
beforeEach ->
rootView.attachToDom()
editor = rootView.activeEditor()
keymap = new (require 'keymap')
originalKeymap = window.keymap
window.keymap = keymap
afterEach ->
window.keymap = originalKeymap
it "returns all keybindings available for focused element", ->
editor.on 'test-event-a', => # nothing
keymap.bindKeys ".editor",
"meta-a": "test-event-a"
"meta-b": "test-event-b"
keybindings = rootView.activeKeybindings()
expect(Object.keys(keybindings).length).toBe 2
expect(keybindings["meta-a"]).toEqual "test-event-a"
describe "when the path of the focused editor's buffer changes", ->
it "changes the document.title and emits an active-editor-path-change event", ->
pathChangeHandler = jasmine.createSpy 'pathChangeHandler'

View File

@@ -1,40 +1,40 @@
$ = require 'jquery'
_ = require 'underscore'
Specificity = require 'specificity'
fs = require 'fs'
Specificity = require 'specificity'
PEG = require 'pegjs'
module.exports =
class BindingSet
selector: null
keystrokeMap: null
commandForEvent: null
keystrokePatternParser: null
parser: null
constructor: (@selector, mapOrFunction) ->
@parser = PEG.buildParser(fs.read(require.resolve 'keystroke-pattern.pegjs'))
@specificity = Specificity(@selector)
@commandForEvent = @buildEventHandler(mapOrFunction)
@keystrokeMap = {}
buildEventHandler: (mapOrFunction) ->
if _.isFunction(mapOrFunction)
mapOrFunction
@commandForEvent = mapOrFunction
else
mapOrFunction = @normalizeKeystrokePatterns(mapOrFunction)
(event) =>
for pattern, command of mapOrFunction
return command if event.keystroke == pattern
@keystrokeMap = @normalizeKeystrokeMap(mapOrFunction)
@commandForEvent = (event) =>
for keystroke, command of @keystrokeMap
return command if event.keystroke == keystroke
null
normalizeKeystrokePatterns: (map) ->
normalizedMap = {}
for pattern, event of map
normalizedMap[@normalizeKeystrokePattern(pattern)] = event
normalizedMap
normalizeKeystrokeMap: (keystrokeMap) ->
normalizeKeystrokeMap = {}
for keystroke, command of keystrokeMap
normalizeKeystrokeMap[@normalizeKeystroke(keystroke)] = command
normalizeKeystrokePattern: (pattern) ->
keys = @parser.parse(pattern)
normalizeKeystrokeMap
normalizeKeystroke: (keystroke) ->
keys = @parser.parse(keystroke)
modifiers = keys[0...-1]
modifiers.sort()
[modifiers..., _.last(keys)].join('-')

View File

@@ -454,7 +454,7 @@ class Editor extends View
return if oldScreenRange.start.row > @lastRenderedScreenRow
maxEndRow = Math.max(@getLastVisibleScreenRow() + @lineOverdraw, @lastRenderedScreenRow)
maxEndRow = Math.max(@getFirstVisibleScreenRow() + @lineOverdraw, @lastRenderedScreenRow)
@gutter.renderLineNumbers(@firstRenderedScreenRow, maxEndRow) if e.lineNumbersChanged
newScreenRange = newScreenRange.copy()

View File

@@ -1,12 +1,13 @@
$ = require 'jquery'
_ = require 'underscore'
fs = require 'fs'
BindingSet = require 'binding-set'
Specificity = require 'specificity'
$ = require 'jquery'
module.exports =
class Keymap
bindingSetsBySelector: null
bindingSets: null
constructor: ->
@bindingSets = []
@@ -26,10 +27,17 @@ class Keymap
bindKeys: (selector, bindings) ->
@bindingSets.unshift(new BindingSet(selector, bindings))
bindKey: (selector, pattern, eventName) ->
bindings = {}
bindings[pattern] = eventName
@bindKeys(selector, bindings)
bindingsForElement: (element) ->
keystrokeMap = {}
currentNode = $(element)
while currentNode.length
bindingSets = @bindingSets.filter (set) -> currentNode.is(set.selector)
bindingSets.sort (a, b) -> b.specificity - a.specificity
_.defaults(keystrokeMap, set.keystrokeMap) for set in bindingSets
currentNode = currentNode.parent()
keystrokeMap
handleKeyEvent: (event) ->
event.keystroke = @keystrokeStringForEvent(event)
@@ -47,9 +55,6 @@ class Keymap
currentNode = currentNode.parent()
true
reset: ->
@bindingSets = []
triggerCommandEvent: (keyEvent, commandName) ->
commandEvent = $.Event(commandName)
commandEvent.keyEvent = keyEvent

View File

@@ -0,0 +1,7 @@
window.keymap.bindKeys '*'
'meta-w': 'close'
'alt-meta-i': 'show-console'
right: 'move-right'
left: 'move-left'
down: 'move-down'
up: 'move-up'

View File

@@ -1,15 +1,3 @@
window.keymap.bindKeys '*'
'meta-s': 'save'
'meta-w': 'close'
'alt-meta-i': 'show-console'
'meta-+': 'increase-font-size'
'meta--': 'decrease-font-size'
right: 'move-right'
left: 'move-left'
down: 'move-down'
up: 'move-up'
window.keymap.bindKeys '.editor',
'meta-s': 'save'
'shift-right': 'select-right'
@@ -39,3 +27,5 @@ window.keymap.bindKeys '.editor',
'meta-]': 'indent-selected-rows'
'meta-{': 'show-previous-buffer'
'meta-}': 'show-next-buffer'
'meta-+': 'increase-font-size'
'meta--': 'decrease-font-size'

View File

@@ -0,0 +1,5 @@
window.keymap.bindKeys '*',
'ctrl-?': 'keybindings-view:attach'
window.keymap.bindKeys ".keybindings-view",
'escape': 'keybindings-view:detach'

View File

@@ -114,6 +114,9 @@ class RootView extends View
if not previousActiveEditor or editor.buffer.path != previousActiveEditor.buffer.path
@trigger 'active-editor-path-change', editor.buffer.path
activeKeybindings: ->
keymap.bindingsForElement(document.activeElement)
setTitle: (title='untitled') ->
document.title = title

View File

@@ -0,0 +1 @@
module.exports = require 'keybindings-view/keybindings-view'

View File

@@ -0,0 +1,31 @@
{View, $$} = require 'space-pen'
module.exports =
class KeybindingsView extends View
@activate: (rootView, state) ->
requireStylesheet 'keybinding-view.css'
@instance = new this(rootView)
@content: (rootView) ->
@div class: 'keybindings-view', tabindex: -1, =>
@ul outlet: 'keybindingList'
initialize: (@rootView) ->
@rootView.on 'keybindings-view:attach', => @attach()
@on 'keybindings-view:detach', => @detach()
attach: ->
@keybindingList.empty()
@keybindingList.append $$ ->
for keystroke, command of rootView.activeKeybindings()
@li =>
@span class: 'keystroke', "#{keystroke}"
@span ":"
@span "#{command}"
@rootView.append(this)
@focus()
detach: ->
super()
@rootView.focus()

View File

@@ -61,4 +61,3 @@ body {
background: #991212;
-webkit-transition: background 200ms ease-out;
}

View File

@@ -0,0 +1,18 @@
.keybindings-view {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
background-color: white;
overflow: scroll;
opacity: 0.9;
}
.keybindings-view li .keystroke {
font-weight: bold;
float: left;
text-align: right;
padding-right: 10px;
width: 200px;
}