From 63181a17c8a82096cc1c5989f56ddc91205972a7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 23 Sep 2014 18:09:28 -0600 Subject: [PATCH] Support activationCommands field in package.json This field mandates selectors in its structure and closely matches the API of `atom.commands.add`. It will supplant `activationEvents` moving forward. --- .../index.coffee | 2 + .../package.cson | 3 + spec/package-manager-spec.coffee | 17 ++++- src/package.coffee | 73 +++++++++++-------- 4 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 spec/fixtures/packages/package-with-activation-commands/index.coffee create mode 100644 spec/fixtures/packages/package-with-activation-commands/package.cson diff --git a/spec/fixtures/packages/package-with-activation-commands/index.coffee b/spec/fixtures/packages/package-with-activation-commands/index.coffee new file mode 100644 index 000000000..d17894702 --- /dev/null +++ b/spec/fixtures/packages/package-with-activation-commands/index.coffee @@ -0,0 +1,2 @@ +module.exports = + activate: -> diff --git a/spec/fixtures/packages/package-with-activation-commands/package.cson b/spec/fixtures/packages/package-with-activation-commands/package.cson new file mode 100644 index 000000000..ae14756ab --- /dev/null +++ b/spec/fixtures/packages/package-with-activation-commands/package.cson @@ -0,0 +1,3 @@ +activationCommands: + '.workspace': 'workspace-command' + '.editor': ['editor-command-1', 'editor-command-2'] diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 90bfb4849..d9a0e5828 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -92,7 +92,7 @@ describe "PackageManager", -> expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1 expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2 - describe "when the package metadata includes activation events", -> + describe "when the package metadata includes `activationEvents`", -> [mainModule, promise, workspaceCommandListener] = [] beforeEach -> @@ -150,6 +150,21 @@ describe "PackageManager", -> runs -> expect(mainModule.activate.callCount).toBe 1 + describe "when the package metadata includes `activationCommands`", -> + it "defers activation until one of the commands is invoked", -> + atom.workspaceView.attachToDom() + mainModule = require './fixtures/packages/package-with-activation-commands/index' + mainModule.commands = [] + spyOn(mainModule, 'activate').andCallThrough() + spyOn(Package.prototype, 'requireMainModule').andCallThrough() + + promise = atom.packages.activatePackage('package-with-activation-commands') + expect(promise.isFulfilled()).not.toBeTruthy() + + atom.workspaceView[0].dispatchEvent(new CustomEvent('workspace-command', bubbles: true)) + + waitsForPromise -> promise + describe "when the package has no main module", -> it "does not throw an exception", -> spyOn(console, "error") diff --git a/src/package.coffee b/src/package.coffee index 6bae82e16..30cd1ad2f 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -99,7 +99,7 @@ class Package @loadMenus() @loadStylesheets() @scopedPropertiesPromise = @loadScopedProperties() - @requireMainModule() unless @hasActivationEvents() + @requireMainModule() unless @hasActivationCommands() catch error console.warn "Failed to load package named '#{@name}'", error.stack ? error @@ -119,8 +119,8 @@ class Package @activationDeferred = Q.defer() @measure 'activateTime', => @activateResources() - if @hasActivationEvents() - @subscribeToActivationEvents() + if @hasActivationCommands() + @subscribeToActivationCommands() else @activateNow() @@ -319,41 +319,50 @@ class Package path.join(@path, 'index') @mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...]) - hasActivationEvents: -> - if _.isArray(@metadata.activationEvents) - return @metadata.activationEvents.some (activationEvent) -> - activationEvent?.length > 0 - else if _.isString(@metadata.activationEvents) - return @metadata.activationEvents.length > 0 - else if _.isObject(@metadata.activationEvents) - for event, selector of @metadata.activationEvents - return true if event.length > 0 and selector.length > 0 - + hasActivationCommands: -> + for selector, commands of @getActivationCommands() + return true if commands.length > 0 false - subscribeToActivationEvents: -> - return unless @metadata.activationEvents? - + subscribeToActivationCommands: -> @activationCommandSubscriptions = new CompositeDisposable - - if _.isArray(@metadata.activationEvents) - for eventName in @metadata.activationEvents + for selector, commands of @getActivationCommands() + for command in commands @activationCommandSubscriptions.add( - atom.commands.add('.workspace', eventName, @handleActivationEvent) - ) - else if _.isString(@metadata.activationEvents) - eventName = @metadata.activationEvents - @activationCommandSubscriptions.add( - atom.commands.add('.workspace', eventName, @handleActivationEvent) - ) - else - for eventName, selector of @metadata.activationEvents - selector ?= '.workspace' - @activationCommandSubscriptions.add( - atom.commands.add(selector, eventName, @handleActivationEvent) + atom.commands.add(selector, command, @handleActivationCommand) ) - handleActivationEvent: (event) => + getActivationCommands: -> + return @activationCommands if @activationCommands? + + @activationCommands = {} + + if @metadata.activationCommands? + for selector, commands of @metadata.activationCommands + @activationCommands[selector] ?= [] + if _.isString(commands) + @activationCommands[selector].push(commands) + else if _.isArray(commands) + @activationCommands[selector].push(commands...) + + if @metadata.activationEvents? + if _.isArray(@metadata.activationEvents) + for eventName in @metadata.activationEvents + @activationCommands['.workspace'] ?= [] + @activationCommands['.workspace'].push(eventName) + else if _.isString(@metadata.activationEvents) + eventName = @metadata.activationEvents + @activationCommands['.workspace'] ?= [] + @activationCommands['.workspace'].push(eventName) + else + for eventName, selector of @metadata.activationEvents + selector ?= '.workspace' + @activationCommands[selector] ?= [] + @activationCommands[selector].push(eventName) + + @activationCommands + + handleActivationCommand: (event) => event.stopImmediatePropagation() @activationCommandSubscriptions.dispose() reenableInvokedListeners = event.disableInvokedListeners()