From ea8781f07d8b57bc086447ee8f23d73c93095789 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 10 Nov 2011 00:05:41 -0800 Subject: [PATCH] new keybinder dispatch method --- extensions/filefinder/filefinder.coffee | 1 - extensions/tabs/tabs.coffee | 3 -- extensions/tree/tree.coffee | 1 - src/atom/app.coffee | 3 -- src/atom/document.coffee | 9 ++-- src/atom/editor.coffee | 1 - src/atom/extension-manager.coffee | 12 ++--- src/atom/window.coffee | 2 - src/startup.coffee | 6 ++- src/stdlib/key-binder.coffee | 67 +++++++++++++------------ 10 files changed, 50 insertions(+), 55 deletions(-) diff --git a/extensions/filefinder/filefinder.coffee b/extensions/filefinder/filefinder.coffee index 30eab6816..043a395bd 100644 --- a/extensions/filefinder/filefinder.coffee +++ b/extensions/filefinder/filefinder.coffee @@ -4,7 +4,6 @@ FilefinderPane = require 'filefinder/filefinder-pane' module.exports = class Filefinder extends Extension constructor: -> - atom.keybinder.register "filefinder", @ atom.keybinder.load require.resolve "filefinder/key-bindings.coffee" @pane = new FilefinderPane @ diff --git a/extensions/tabs/tabs.coffee b/extensions/tabs/tabs.coffee index d3a7376c4..6172658c0 100644 --- a/extensions/tabs/tabs.coffee +++ b/extensions/tabs/tabs.coffee @@ -8,7 +8,6 @@ fs = require 'fs' module.exports = class Tabs extends Extension constructor: () -> - atom.keybinder.register "tabs", @ atom.keybinder.load require.resolve "tabs/key-bindings.coffee" @pane = new TabsPane @ @@ -31,5 +30,3 @@ class Tabs extends Extension startup: -> @pane.show() - for path, buffer of window.editor.buffers - @pane.addTab path diff --git a/extensions/tree/tree.coffee b/extensions/tree/tree.coffee index b706e8967..3f98a33aa 100644 --- a/extensions/tree/tree.coffee +++ b/extensions/tree/tree.coffee @@ -15,7 +15,6 @@ class Tree extends Extension paths: [] constructor: -> - atom.keybinder.register "tree", @ atom.keybinder.load require.resolve "tree/key-bindings.coffee" # watch the root dir diff --git a/src/atom/app.coffee b/src/atom/app.coffee index 46ef18101..3d3e718cc 100644 --- a/src/atom/app.coffee +++ b/src/atom/app.coffee @@ -1,8 +1,5 @@ module.exports = class App - constructor: -> - atom.keybinder.register "app", this - open: (path) -> OSX.NSApp.open path diff --git a/src/atom/document.coffee b/src/atom/document.coffee index b71d806dc..d1febe967 100644 --- a/src/atom/document.coffee +++ b/src/atom/document.coffee @@ -7,10 +7,11 @@ class Document extends Pane @handlers: {} @handler: (path) -> - for handler, test of Document.handlers - return handler if test path - @register: (cb) -> - Document.handlers[this] = cb + for name, {test, handler} of Document.handlers + return new handler path if test path + null + @register: (test) -> + Document.handlers[@name] = {test, handler: this} open: -> close: -> diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index f04094fae..01e1857ee 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -17,7 +17,6 @@ class Editor extends Document constructor: (@path) -> super() - atom.keybinder.register "editor", @ @show() diff --git a/src/atom/extension-manager.coffee b/src/atom/extension-manager.coffee index 087211575..94b64cdcd 100644 --- a/src/atom/extension-manager.coffee +++ b/src/atom/extension-manager.coffee @@ -9,25 +9,25 @@ class ExtensionManager atom.on 'window:close', @unloadExtensions loadExtensions: => - extension.shutdown() for name, extension of @extensions - @extensions = {} + extension.shutdown() for name, extension of atom.extensions + atom.extensions = {} extensionPaths = fs.list require.resourcePath + "/extensions" for extensionPath in extensionPaths when fs.isDirectory extensionPath try extension = require extensionPath - @extensions[extension.name] = new extension + atom.extensions[extension.name] = new extension catch error console.warn "Loading Extension '#{fs.base extensionPath}' failed." console.warn error # After all the extensions are created, start them up. - for name, extension of @extensions + for name, extension of atom.extensions try extension.startup() catch error - console.warn "Extension #{extension::name} failed to startup." + console.warn "Extension #{extension.constructor.name} failed to startup." console.warn error unloadExtensions: => - extension.shutdown() for name, extension of @extensions \ No newline at end of file + extension.shutdown() for name, extension of atom.extensions \ No newline at end of file diff --git a/src/atom/window.coffee b/src/atom/window.coffee index 943795764..7c64f249d 100644 --- a/src/atom/window.coffee +++ b/src/atom/window.coffee @@ -9,8 +9,6 @@ windowAdditions = path: null startup: -> - atom.keybinder.register "window", window - @path = $atomController.path.toString() @setTitle (_.last @path.split '/') or 'Untitled Document' diff --git a/src/startup.coffee b/src/startup.coffee index cf16e7901..c19fb0a9d 100644 --- a/src/startup.coffee +++ b/src/startup.coffee @@ -22,7 +22,8 @@ for name, method of atom.event atom.keybinder = new KeyBinder atom.settings = new Settings -atom.extensions = new ExtensionManager +atom.extensions = {} +atom.extensionManager = new ExtensionManager atom.app = new App # atom.open, atom.close, etc. @@ -30,7 +31,8 @@ for name, method of atom.app atom[name] = atom.app[name] atom.path = $atomController.path.toString() -atom.document = new Document.handler atom.path +atom.document = Document.handler atom.path +atom.document ?= new Editor require 'window' window.startup() diff --git a/src/stdlib/key-binder.coffee b/src/stdlib/key-binder.coffee index 47ce157be..60de147ca 100644 --- a/src/stdlib/key-binder.coffee +++ b/src/stdlib/key-binder.coffee @@ -5,18 +5,16 @@ Watcher = require 'watcher' module.exports = class KeyBinder + # keymaps are name => { binding: method } mappings + keymaps: {} + constructor: -> atom.on 'window:load', -> atom.keybinder.load require.resolve "key-bindings.coffee" if fs.isFile "~/.atomicity/key-bindings.coffee" atom.keybinder.load "~/.atomicity/key-bindings.coffee" - bindings: {} - - scopes: {} - register: (name, scope) -> - @scopes[name] = scope load: (path) -> try @@ -29,47 +27,52 @@ class KeyBinder @load path json = CoffeeScript.eval "return " + (fs.read path) - for scopeName, bindings of json - @create scopeName, binding, method for binding, method of bindings + # Iterate in reverse order scopes are declared. + # Scope at the top of the file is checked last. + for name in _.keys(json).reverse() + bindings = json[name] + @keymaps[name] ?= {} + for binding, method of bindings + @keymaps[name][@bindingParser binding] = method catch error - console.error "#{@name}: Could not load key bindings at `#{path}`. #{error}" - - create: (scope, binding, method) -> - if typeof scope is "string" - throw "#{@name}: Unknown scope `#{scope}`" unless @scopes[scope] - scope = @scopes[scope] - - callback = if _.isFunction method - -> method scope - else if scope[method] - -> scope[method]() - else - throw "#{@name}: '#{method}' not found found in scope #{scope}" - - callbacks = @bindings[@bindingParser binding] ?= [] - - callbacks.push callback + console.error "Can't load key bindings at `#{path}`. #{error}" handleEvent: (event) -> keys = [] - keys.push @modifierKeys.command if event.modifierFlags & OSX.NSCommandKeyMask - keys.push @modifierKeys.control if event.modifierFlags & OSX.NSControlKeyMask - keys.push @modifierKeys.alt if event.modifierFlags & OSX.NSAlternateKeyMask + if event.modifierFlags & OSX.NSCommandKeyMask + keys.push @modifierKeys.command + if event.modifierFlags & OSX.NSControlKeyMask + keys.push @modifierKeys.control + if event.modifierFlags & OSX.NSAlternateKeyMask + keys.push @modifierKeys.alt keys.push event.charactersIgnoringModifiers.charCodeAt 0 binding = keys.sort().join "-" - callbacks = @bindings[binding] - return false if not callbacks + for scope, bindings of @keymaps + break if method = bindings[binding] + return false if not method - # Only use the most recently added binding try - _.last(callbacks)() + @triggerBinding scope, method catch e console.warn "Failed to run binding #{@bindingFromAscii binding}. #{e}" true + responders: -> + _.flatten [ (_.values atom.extensions), atom.document, window, atom ] + + triggerBinding: (scope, method) -> + responder = _.detect @responders(), (responder) -> + (scope is 'window' and responder is window) or + responder.constructor.name.toLowerCase() is scope + if responder + if _.isFunction method + method responder + else + responder[method]() + bindingParser: (binding) -> keys = binding.trim().split '-' @@ -101,7 +104,7 @@ class KeyBinder asciiKeys = binding.split '-' keys = [] - for asciiKey in asciiKeys + for asciiKey in asciiKeys.reverse() key = inverseModifierKeys[asciiKey] key ?= inverseNamedKeys[asciiKey] key ?= String.fromCharCode asciiKey