Merge pull request #1539 from atom/cj-move-openers-to-workspace

Cj move openers to workspace
This commit is contained in:
Corey Johnson
2014-02-13 14:23:11 -08:00
5 changed files with 180 additions and 178 deletions

View File

@@ -86,7 +86,7 @@
"image-view": "0.21.0",
"keybinding-resolver": "0.10.0",
"link": "0.17.0",
"markdown-preview": "0.28.0",
"markdown-preview": "0.29.0",
"metrics": "0.26.0",
"package-generator": "0.26.0",
"release-notes": "0.20.0",

View File

@@ -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

View File

@@ -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.resolve('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] = []

View File

@@ -30,11 +30,12 @@ class Project extends Model
constructor: ({path, @buffers}={}) ->
@buffers ?= []
@openers = []
for buffer in @buffers
do (buffer) =>
buffer.once 'destroyed', => @removeBuffer(buffer)
@openers = []
@editors = []
@setPath(path)
@@ -46,23 +47,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 +113,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,34 +121,21 @@ 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
filePath = @resolve(filePath)
@buildEditorForBuffer(@bufferForPathSync(filePath), options)
resource or @buildEditorForBuffer(@bufferForPathSync(filePath), options)
# Public: Retrieves all {Editor}s for all open files.
#
# Returns an {Array} of {Editor}s.
getEditors: ->
new Array(@editors...)
# Public: Add the given {Editor}.
# Add the given {Editor}.
addEditor: (editor) ->
@editors.push editor
@emit 'editor-created', editor
# Public: Return and removes the given {Editor}.
# Return and removes the given {Editor}.
removeEditor: (editor) ->
_.remove(@editors, editor)
@@ -330,10 +301,6 @@ class Project extends Model
@addEditor(editor)
editor
eachEditor: (callback) ->
callback(editor) for editor in @getEditors()
@on 'editor-created', (editor) -> callback(editor)
eachBuffer: (args...) ->
subscriber = args.shift() if args.length > 1
callback = args.shift()
@@ -343,3 +310,20 @@ class Project extends Model
subscriber.subscribe this, 'buffer-created', (buffer) -> callback(buffer)
else
@on 'buffer-created', (buffer) -> callback(buffer)
# Deprecated: delegate
registerOpener: (opener) ->
@openers.push(opener)
# Deprecated: delegate
unregisterOpener: (opener) ->
_.remove(@openers, opener)
# Deprecated: delegate
eachEditor: (callback) ->
callback(editor) for editor in @getEditors()
@on 'editor-created', (editor) -> callback(editor)
# Deprecated: delegate
getEditors: ->
new Array(@editors...)

View File

@@ -27,7 +27,7 @@ class Workspace extends Model
constructor: ->
super
@subscribe @paneContainer, 'item-destroyed', @onPaneItemDestroyed
atom.project.registerOpener (filePath) =>
@registerOpener (filePath) =>
switch filePath
when 'atom://.atom/stylesheet'
@open(atom.themes.getUserStylesheetPath())
@@ -48,9 +48,20 @@ class Workspace extends Model
paneContainer: @paneContainer.serialize()
fullScreen: atom.isFullScreen()
# Public: Calls callback for every existing {Editor} and for all new {Editors}
# that are created.
#
# callback - A {Function} with an {Editor} as its only argument
eachEditor: (callback) ->
atom.project.eachEditor(callback)
# Public: Returns an {Array} of all open {Editor}s.
getEditors: ->
atom.project.getEditors()
# 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 +69,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,42 +88,73 @@ 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})
else
editor = atom.project.openSync()
item = @activePane.itemForUri(uri)
if uri
item ?= opener(atom.project.resolve(uri), options) for opener in @getOpeners() when !item
item ?= atom.project.openSync(uri, {initialLine})
@activePane.activateItem(editor)
@itemOpened(editor)
@activePane.activateItem(item)
@itemOpened(item)
@activePane.activate() if activatePane
editor
item
openUriInPane: (uri, pane, options={}) ->
changeFocus = options.changeFocus ? true
item = pane.itemForUri(uri)
if uri
item ?= opener(atom.project.resolve(uri), options) for opener in @getOpeners() when !item
item ?= atom.project.open(uri, options)
Q(item)
.then (item) =>
if not pane
pane = new Pane(items: [item])
@paneContainer.root = pane
@itemOpened(item)
pane.activateItem(item)
pane.activate() if changeFocus
@emit "uri-opened"
item
.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) ->
atom.project.registerOpener(opener)
# Public: Remove a registered opener.
unregisterOpener: (opener) ->
atom.project.unregisterOpener(opener)
getOpeners: ->
atom.project.openers
# Public: save the active item.
saveActivePaneItem: ->
@activePane?.saveActiveItem()