From ee09eee374144587c61ac35af3ef7c8b052152a8 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Wed, 12 Feb 2014 16:56:00 -0800 Subject: [PATCH] Move (un)registerOpener to Workspace --- spec/project-spec.coffee | 171 +++++++++++++++---------------------- spec/workspace-spec.coffee | 16 ++++ src/project.coffee | 43 +++------- src/workspace.coffee | 68 ++++++++++----- 4 files changed, 139 insertions(+), 159 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 1ac76e204..e33413f97 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -72,7 +72,7 @@ describe "Project", -> expect(atom.project.getEditors()[1]).toBe editor2 describe ".openSync(path)", -> - [fooOpener, barOpener, absolutePath, newBufferHandler, newEditorHandler] = [] + [absolutePath, newBufferHandler, newEditorHandler] = [] beforeEach -> absolutePath = require.resolve('./fixtures/dir/a') newBufferHandler = jasmine.createSpy('newBufferHandler') @@ -80,129 +80,92 @@ describe "Project", -> newEditorHandler = jasmine.createSpy('newEditorHandler') atom.project.on 'editor-created', newEditorHandler - fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/) - barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//) - atom.project.registerOpener(fooOpener) - atom.project.registerOpener(barOpener) + describe "when given an absolute path that hasn't been opened previously", -> + it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", -> + editor = atom.project.openSync(absolutePath) + expect(editor.buffer.getPath()).toBe absolutePath + expect(newBufferHandler).toHaveBeenCalledWith editor.buffer + expect(newEditorHandler).toHaveBeenCalledWith editor - afterEach -> - atom.project.unregisterOpener(fooOpener) - atom.project.unregisterOpener(barOpener) + describe "when given a relative path that hasn't been opened previously", -> + it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", -> + editor = atom.project.openSync('a') + expect(editor.buffer.getPath()).toBe absolutePath + expect(newBufferHandler).toHaveBeenCalledWith editor.buffer + expect(newEditorHandler).toHaveBeenCalledWith editor - describe "when passed a path that doesn't match a custom opener", -> - describe "when given an absolute path that hasn't been opened previously", -> - it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", -> - editor = atom.project.openSync(absolutePath) + describe "when passed the path to a buffer that has already been opened", -> + it "returns a new edit session containing previously opened buffer and emits a 'editor-created' event", -> + editor = atom.project.openSync(absolutePath) + newBufferHandler.reset() + expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer + expect(atom.project.openSync('a').buffer).toBe editor.buffer + expect(newBufferHandler).not.toHaveBeenCalled() + expect(newEditorHandler).toHaveBeenCalledWith editor + + describe "when not passed a path", -> + it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", -> + editor = atom.project.openSync() + expect(editor.buffer.getPath()).toBeUndefined() + expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer) + expect(newEditorHandler).toHaveBeenCalledWith editor + + describe ".open(path)", -> + [absolutePath, newBufferHandler, newEditorHandler] = [] + + beforeEach -> + absolutePath = require.resolve('./fixtures/dir/a') + newBufferHandler = jasmine.createSpy('newBufferHandler') + atom.project.on 'buffer-created', newBufferHandler + newEditorHandler = jasmine.createSpy('newEditorHandler') + atom.project.on 'editor-created', newEditorHandler + + describe "when given an absolute path that isn't currently open", -> + it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", -> + editor = null + waitsForPromise -> + atom.project.open(absolutePath).then (o) -> editor = o + + runs -> expect(editor.buffer.getPath()).toBe absolutePath expect(newBufferHandler).toHaveBeenCalledWith editor.buffer expect(newEditorHandler).toHaveBeenCalledWith editor - describe "when given a relative path that hasn't been opened previously", -> - it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", -> - editor = atom.project.openSync('a') + describe "when given a relative path that isn't currently opened", -> + it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", -> + editor = null + waitsForPromise -> + atom.project.open(absolutePath).then (o) -> editor = o + + runs -> expect(editor.buffer.getPath()).toBe absolutePath expect(newBufferHandler).toHaveBeenCalledWith editor.buffer expect(newEditorHandler).toHaveBeenCalledWith editor - describe "when passed the path to a buffer that has already been opened", -> - it "returns a new edit session containing previously opened buffer and emits a 'editor-created' event", -> - editor = atom.project.openSync(absolutePath) + describe "when passed the path to a buffer that is currently opened", -> + it "returns a new edit session containing currently opened buffer and emits a 'editor-created' event", -> + editor = null + waitsForPromise -> + atom.project.open(absolutePath).then (o) -> editor = o + + runs -> newBufferHandler.reset() expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer expect(atom.project.openSync('a').buffer).toBe editor.buffer expect(newBufferHandler).not.toHaveBeenCalled() expect(newEditorHandler).toHaveBeenCalledWith editor - describe "when not passed a path", -> - it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", -> - editor = atom.project.openSync() + describe "when not passed a path", -> + it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", -> + editor = null + waitsForPromise -> + atom.project.open().then (o) -> editor = o + + runs -> expect(editor.buffer.getPath()).toBeUndefined() expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer) expect(newEditorHandler).toHaveBeenCalledWith editor - describe "when passed a path that matches a custom opener", -> - it "returns the resource returned by the custom opener", -> - pathToOpen = atom.project.resolve('a.foo') - expect(atom.project.openSync(pathToOpen, hey: "there")).toEqual { foo: pathToOpen, options: {hey: "there"} } - expect(atom.project.openSync("bar://baz")).toEqual { bar: "bar://baz" } - - describe ".open(path)", -> - [fooOpener, barOpener, absolutePath, newBufferHandler, newEditorHandler] = [] - - beforeEach -> - absolutePath = require.resolve('./fixtures/dir/a') - newBufferHandler = jasmine.createSpy('newBufferHandler') - atom.project.on 'buffer-created', newBufferHandler - newEditorHandler = jasmine.createSpy('newEditorHandler') - atom.project.on 'editor-created', newEditorHandler - - fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/) - barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//) - atom.project.registerOpener(fooOpener) - atom.project.registerOpener(barOpener) - - afterEach -> - atom.project.unregisterOpener(fooOpener) - atom.project.unregisterOpener(barOpener) - - describe "when passed a path that doesn't match a custom opener", -> - describe "when given an absolute path that isn't currently open", -> - it "returns a new edit session for the given path and emits 'buffer-created' and 'editor-created' events", -> - editor = null - waitsForPromise -> - atom.project.open(absolutePath).then (o) -> editor = o - - runs -> - expect(editor.buffer.getPath()).toBe absolutePath - expect(newBufferHandler).toHaveBeenCalledWith editor.buffer - expect(newEditorHandler).toHaveBeenCalledWith editor - - describe "when given a relative path that isn't currently opened", -> - it "returns a new edit session for the given path (relative to the project root) and emits 'buffer-created' and 'editor-created' events", -> - editor = null - waitsForPromise -> - atom.project.open(absolutePath).then (o) -> editor = o - - runs -> - expect(editor.buffer.getPath()).toBe absolutePath - expect(newBufferHandler).toHaveBeenCalledWith editor.buffer - expect(newEditorHandler).toHaveBeenCalledWith editor - - describe "when passed the path to a buffer that is currently opened", -> - it "returns a new edit session containing currently opened buffer and emits a 'editor-created' event", -> - editor = null - waitsForPromise -> - atom.project.open(absolutePath).then (o) -> editor = o - - runs -> - newBufferHandler.reset() - expect(atom.project.openSync(absolutePath).buffer).toBe editor.buffer - expect(atom.project.openSync('a').buffer).toBe editor.buffer - expect(newBufferHandler).not.toHaveBeenCalled() - expect(newEditorHandler).toHaveBeenCalledWith editor - - describe "when not passed a path", -> - it "returns a new edit session and emits 'buffer-created' and 'editor-created' events", -> - editor = null - waitsForPromise -> - atom.project.open().then (o) -> editor = o - - runs -> - expect(editor.buffer.getPath()).toBeUndefined() - expect(newBufferHandler).toHaveBeenCalledWith(editor.buffer) - expect(newEditorHandler).toHaveBeenCalledWith editor - - describe "when passed a path that matches a custom opener", -> - it "returns the resource returned by the custom opener", -> - waitsForPromise -> - pathToOpen = atom.project.resolve('a.foo') - atom.project.open(pathToOpen, hey: "there").then (item) -> - expect(item).toEqual { foo: pathToOpen, options: {hey: "there"} } - - waitsForPromise -> - atom.project.open("bar://baz").then (item) -> - expect(item).toEqual { bar: "bar://baz" } - it "returns number of read bytes as progress indicator", -> filePath = atom.project.resolve 'a' totalBytes = 0 diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index fd99c3d74..3f3a04698 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -126,6 +126,22 @@ describe "Workspace", -> expect(pane1.items).toEqual [] expect(pane2.items).toEqual [editor] + describe "when passed a path that matches a custom opener", -> + it "returns the resource returned by the custom opener", -> + fooOpener = (pathToOpen, options) -> { foo: pathToOpen, options } if pathToOpen?.match(/\.foo/) + barOpener = (pathToOpen) -> { bar: pathToOpen } if pathToOpen?.match(/^bar:\/\//) + workspace.registerOpener(fooOpener) + workspace.registerOpener(barOpener) + + waitsForPromise -> + pathToOpen = atom.project.relativize('a.foo') + workspace.open(pathToOpen, hey: "there").then (item) -> + expect(item).toEqual { foo: pathToOpen, options: {hey: "there"} } + + waitsForPromise -> + workspace.open("bar://baz").then (item) -> + expect(item).toEqual { bar: "bar://baz" } + describe "::openSync(uri, options)", -> [activePane, initialItemCount] = [] diff --git a/src/project.coffee b/src/project.coffee index f69af88f5..0f93bb520 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -34,7 +34,6 @@ class Project extends Model do (buffer) => buffer.once 'destroyed', => @removeBuffer(buffer) - @openers = [] @editors = [] @setPath(path) @@ -46,23 +45,6 @@ class Project extends Model params.buffers = params.buffers.map (bufferState) -> atom.deserializers.deserialize(bufferState) params - # Public: Register an opener for project files. - # - # An {Editor} will be used if no openers return a value. - # - # ## Example - # ```coffeescript - # atom.project.registerOpener (filePath) -> - # if path.extname(filePath) is '.toml' - # return new TomlEditor(filePath) - # ``` - # - # opener - A {Function} to be called when a path is being opened. - registerOpener: (opener) -> @openers.push(opener) - - # Public: Remove a previously registered opener. - unregisterOpener: (opener) -> _.remove(@openers, opener) - destroyed: -> editor.destroy() for editor in @getEditors() buffer.destroy() for buffer in @getBuffers() @@ -129,7 +111,7 @@ class Project extends Model contains: (pathToCheck) -> @rootDirectory?.contains(pathToCheck) ? false - # Public: Given a path to a file, this constructs and associates a new + # Given a path to a file, this constructs and associates a new # {Editor}, showing the file. # # filePath - The {String} path of the file to associate with. @@ -137,21 +119,14 @@ class Project extends Model # # Returns a promise that resolves to an {Editor}. open: (filePath, options={}) -> - filePath = @resolve(filePath) ? '' - resource = opener(filePath, options) for opener in @openers when !resource + filePath = @resolve(filePath) + @bufferForPath(filePath).then (buffer) => + @buildEditorForBuffer(buffer, options) - if resource - Q(resource) - else - @bufferForPath(filePath).then (buffer) => - @buildEditorForBuffer(buffer, options) - - # Only be used in specs + # Deprecated openSync: (filePath, options={}) -> - filePath = @resolve(filePath) ? '' - resource = opener(filePath, options) for opener in @openers when !resource - - resource or @buildEditorForBuffer(@bufferForPathSync(filePath), options) + filePath = @resolve(filePath) + @buildEditorForBuffer(@bufferForPathSync(filePath), options) # Public: Retrieves all {Editor}s for all open files. # @@ -343,3 +318,7 @@ class Project extends Model subscriber.subscribe this, 'buffer-created', (buffer) -> callback(buffer) else @on 'buffer-created', (buffer) -> callback(buffer) + + # Deprecated delegates + registerOpener: -> atom.workspaceView.model.registerOpener(arguments) + unregisterOpener: -> atom.workspaceView.model.unregisterOpener(arguments) diff --git a/src/workspace.coffee b/src/workspace.coffee index 4409ed95d..13df95c6b 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -26,8 +26,9 @@ class Workspace extends Model constructor: -> super + @openers = [] @subscribe @paneContainer, 'item-destroyed', @onPaneItemDestroyed - atom.project.registerOpener (filePath) => + @registerOpener (filePath) => switch filePath when 'atom://.atom/stylesheet' @open(atom.themes.getUserStylesheetPath()) @@ -50,7 +51,7 @@ class Workspace extends Model # Public: Asynchronously opens a given a filepath in Atom. # - # filePath - A {String} file path. + # uri - A {String} uri. # options - An options {Object} (default: {}). # :initialLine - A {Number} indicating which line number to open to. # :split - A {String} ('left' or 'right') that opens the filePath in a new @@ -58,16 +59,13 @@ class Workspace extends Model # :changeFocus - A {Boolean} that allows the filePath to be opened without # changing focus. # :searchAllPanes - A {Boolean} that will open existing editors from any pane - # if the filePath is already open (default: false) + # if the uri is already open (default: false) # # Returns a promise that resolves to the {Editor} for the file URI. - open: (filePath, options={}) -> - changeFocus = options.changeFocus ? true - filePath = atom.project.resolve(filePath) - initialLine = options.initialLine + open: (uri, options={}) -> searchAllPanes = options.searchAllPanes split = options.split - uri = atom.project.relativize(filePath) + uri = atom.project.relativize(uri) ? '' pane = switch split when 'left' @@ -80,29 +78,18 @@ class Workspace extends Model else @activePane - Q(pane.itemForUri(uri) ? atom.project.open(filePath, options)) - .then (editor) => - if not pane - pane = new Pane(items: [editor]) - @paneContainer.root = pane - - @itemOpened(editor) - pane.activateItem(editor) - pane.activate() if changeFocus - @emit "uri-opened" - editor - .catch (error) -> - console.error(error.stack ? error) + @openUriInPane(uri, pane, options) # Only used in specs openSync: (uri, options={}) -> {initialLine} = options # TODO: Remove deprecated changeFocus option activatePane = options.activatePane ? options.changeFocus ? true - uri = atom.project.relativize(uri) + uri = atom.project.relativize(uri) ? '' if uri? - editor = @activePane.itemForUri(uri) ? atom.project.openSync(uri, {initialLine}) + item = opener(uri, options) for opener in @openers when !item + editor = item ? @activePane.itemForUri(uri) ? atom.project.openSync(uri, {initialLine}) else editor = atom.project.openSync() @@ -111,11 +98,46 @@ class Workspace extends Model @activePane.activate() if activatePane editor + openUriInPane: (uri, pane, options={}) -> + changeFocus = options.changeFocus ? true + item = opener(uri, options) for opener in @openers when !item + promise = Q(item ? pane.itemForUri(uri) ? atom.project.open(uri, options)) + + promise + .then (editor) => + if not pane + pane = new Pane(items: [editor]) + @paneContainer.root = pane + @itemOpened(editor) + pane.activateItem(editor) + pane.activate() if changeFocus + @emit "uri-opened" + editor + .catch (error) -> + console.error(error.stack ? error) + # Public: Reopens the last-closed item uri if it hasn't already been reopened. reopenItemSync: -> if uri = @destroyedItemUris.pop() @openSync(uri) + # Public: Register an opener for a uri. + # + # An {Editor} will be used if no openers return a value. + # + # ## Example + # ```coffeescript + # atom.project.registerOpener (uri) -> + # if path.extname(uri) is '.toml' + # return new TomlEditor(uri) + # ``` + # + # opener - A {Function} to be called when a path is being opened. + registerOpener: (opener) -> @openers.push(opener) + + # Public: Remove a registered opener. + unregisterOpener: (opener) -> _.remove(@openers, opener) + # Public: save the active item. saveActivePaneItem: -> @activePane?.saveActiveItem()