diff --git a/package.json b/package.json index 45599fd4c..1d3b64a96 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "serializable": "^1", "service-hub": "^0.1.0", "space-pen": "3.8.2", + "stacktrace-parser": "0.1.1", "temp": "0.7.0", "text-buffer": "^3.8.4", "theorist": "^1.0.2", diff --git a/spec/fixtures/packages/package-with-deprecated-pane-item-method/index.coffee b/spec/fixtures/packages/package-with-deprecated-pane-item-method/index.coffee new file mode 100644 index 000000000..16d826929 --- /dev/null +++ b/spec/fixtures/packages/package-with-deprecated-pane-item-method/index.coffee @@ -0,0 +1,5 @@ +class TestItem + getUri: -> "test" + +exports.activate = -> + atom.workspace.addOpener -> new TestItem diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 527c06971..16bcdbcab 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -6,6 +6,7 @@ platform = require './spec-helper-platform' _ = require 'underscore-plus' fstream = require 'fstream' fs = require 'fs-plus' +Grim = require 'grim' describe "Workspace", -> workspace = null @@ -250,6 +251,21 @@ describe "Workspace", -> runs -> expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor + it "records a deprecation warning on the appropriate package if the item has a ::getUri method instead of ::getURI", -> + jasmine.snapshotDeprecations() + + waitsForPromise -> atom.packages.activatePackage('package-with-deprecated-pane-item-method') + + waitsForPromise -> + atom.workspace.open("test") + + runs -> + deprecations = Grim.getDeprecations() + expect(deprecations.length).toBe 1 + expect(deprecations[0].message).toBe "Pane item with class `TestItem` should implement `::getURI` instead of `::getUri`." + expect(deprecations[0].getStacks()[0].metadata.packageName).toBe "package-with-deprecated-pane-item-method" + jasmine.restoreDeprecationsSnapshot() + describe "::reopenItem()", -> it "opens the uri associated with the last closed pane that isn't currently open", -> pane = workspace.getActivePane() diff --git a/src/pane.coffee b/src/pane.coffee index 44cc20cc7..e2e61ca95 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -340,9 +340,6 @@ class Pane extends Model addItem: (item, index=@getActiveItemIndex() + 1) -> return if item in @items - if typeof item.getUri is 'function' and typeof item.getURI isnt 'function' - Grim.deprecate("Pane items should implement `::getURI` instead of `::getUri`.") - if typeof item.on is 'function' @subscribe item, 'destroyed', => @removeItem(item, true) diff --git a/src/workspace.coffee b/src/workspace.coffee index d14b79673..a6637ffc3 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -1,12 +1,14 @@ {deprecate} = require 'grim' _ = require 'underscore-plus' -{join} = require 'path' +path = require 'path' +{join} = path {Model} = require 'theorist' Q = require 'q' Serializable = require 'serializable' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' Grim = require 'grim' fs = require 'fs-plus' +StackTraceParser = require 'stacktrace-parser' TextEditor = require './text-editor' PaneContainer = require './pane-container' Pane = require './pane' @@ -495,8 +497,17 @@ class Workspace extends Model # Returns a {Disposable} on which `.dispose()` can be called to remove the # opener. addOpener: (opener) -> - @openers.push(opener) - new Disposable => _.remove(@openers, opener) + packageName = @getCallingPackageName() + + wrappedOpener = (uri, options) -> + item = opener(uri, options) + if item? and typeof item.getUri is 'function' and typeof item.getURI isnt 'function' + Grim.deprecate("Pane item with class `#{item.constructor.name}` should implement `::getURI` instead of `::getUri`.", {packageName}) + item + + @openers.push(wrappedOpener) + new Disposable => _.remove(@openers, wrappedOpener) + registerOpener: (opener) -> Grim.deprecate("Call Workspace::addOpener instead") @addOpener(opener) @@ -508,6 +519,34 @@ class Workspace extends Model getOpeners: -> @openers + getCallingPackageName: -> + error = new Error + Error.captureStackTrace(error) + stack = StackTraceParser.parse(error.stack) + + packagePaths = @getPackagePathsByPackageName() + + for i in [0...stack.length] + stackFramePath = stack[i].file + + # Empty when it was run from the dev console + return unless stackFramePath + + for packageName, packagePath of packagePaths + continue if stackFramePath is 'node.js' + relativePath = path.relative(packagePath, stackFramePath) + return packageName unless /^\.\./.test(relativePath) + return + + getPackagePathsByPackageName: -> + packagePathsByPackageName = {} + for pack in atom.packages.getLoadedPackages() + packagePath = pack.path + if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1 + packagePath = fs.realpathSync(packagePath) + packagePathsByPackageName[pack.name] = packagePath + packagePathsByPackageName + ### Section: Pane Items ###