From adbcb9f49e2c9255d7f07660d3df93b9da33ecfc Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 2 Nov 2012 14:13:03 -0600 Subject: [PATCH] Only consider BindingSets with a binding for first keystroke of event The keymap was slow because it would find the binding sets with matching selectors for every ancestor of every keydown event. The problem was, it was considering a lot of binding sets that didn't even have a binding for the event in question. Now we index all binding sets on what bindings they contain, and filter them by that first. Rejecting an event that has no bindings is almost instantaneous now. --- src/app/keymap.coffee | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/app/keymap.coffee b/src/app/keymap.coffee index 241a96f86..462ccb85b 100644 --- a/src/app/keymap.coffee +++ b/src/app/keymap.coffee @@ -8,10 +8,12 @@ Specificity = require 'specificity' module.exports = class Keymap bindingSets: null + bindingSetsByFirstKeystroke: null queuedKeystrokes: null constructor: -> @bindingSets = [] + @bindingSetsByFirstKeystroke = {} bindDefaultKeys: -> @bindKeys "*", @@ -25,8 +27,12 @@ class Keymap $(document).on 'open', => atom.open() bindKeys: (selector, bindings) -> - index = @bindingSets.length - @bindingSets.unshift(new BindingSet(selector, bindings, index)) + bindingSet = new BindingSet(selector, bindings, @bindingSets.length) + @bindingSets.unshift(bindingSet) + for keystrokes of bindingSet.commandsByKeystrokes + keystroke = keystrokes.split(' ')[0] # only index by first keystroke + @bindingSetsByFirstKeystroke[keystroke] ?= [] + @bindingSetsByFirstKeystroke[keystroke].push(bindingSet) bindingsForElement: (element) -> keystrokeMap = {} @@ -43,9 +49,14 @@ class Keymap event.keystrokes = @multiKeystrokeStringForEvent(event) isMultiKeystroke = @queuedKeystrokes? @queuedKeystrokes = null + + firstKeystroke = event.keystrokes.split(' ')[0] + bindingSetsForFirstKeystroke = @bindingSetsByFirstKeystroke[firstKeystroke] + return true unless bindingSetsForFirstKeystroke? + currentNode = $(event.target) while currentNode.length - candidateBindingSets = @bindingSetsForNode(currentNode) + candidateBindingSets = @bindingSetsForNode(currentNode, bindingSetsForFirstKeystroke) for bindingSet in candidateBindingSets command = bindingSet.commandForEvent(event) if command @@ -61,8 +72,8 @@ class Keymap !isMultiKeystroke - bindingSetsForNode: (node) -> - bindingSets = @bindingSets.filter (set) -> node.is(set.selector) + bindingSetsForNode: (node, candidateBindingSets = @bindingSets) -> + bindingSets = candidateBindingSets.filter (set) -> node.is(set.selector) bindingSets.sort (a, b) -> if b.specificity == a.specificity b.index - a.index