Remove telepath from Project, WorkspaceView, and Pane*

This commit is contained in:
Nathan Sobo
2014-01-03 16:23:23 -07:00
parent 821debcb85
commit bc65137911
16 changed files with 97 additions and 190 deletions

View File

@@ -257,7 +257,7 @@ describe "Git", ->
it "subscribes to all the serialized buffers in the project", ->
atom.project.openSync('sample.js')
project2 = atom.project.testPersistence()
project2 = atom.project.testSerialization()
buffer = project2.getBuffers()[0]
waitsFor ->

View File

@@ -677,12 +677,12 @@ describe "Pane", ->
describe "serialization", ->
it "can serialize and deserialize the pane and all its items", ->
newPane = atom.deserializers.deserialize(pane.serialize().testPersistence())
newPane = pane.testSerialization()
expect(newPane.getItems()).toEqual [view1, editor1, view2, editor2]
it "restores the active item on deserialization", ->
pane.showItem(editor2)
newPane = atom.deserializers.deserialize(pane.serialize().testPersistence())
newPane = pane.testSerialization()
expect(newPane.activeItem).toEqual editor2
it "does not show items that cannot be deserialized", ->
@@ -693,7 +693,7 @@ describe "Pane", ->
pane.showItem(new Unserializable)
state = pane.serialize().testPersistence()
state = pane.testSerialization()
newPane = atom.deserializers.deserialize(state)
expect(newPane.activeItem).toEqual pane.items[0]
expect(newPane.items.length).toBe pane.items.length - 1
@@ -702,13 +702,13 @@ describe "Pane", ->
container.attachToDom()
pane.focus()
container2 = atom.deserializers.deserialize(container.serialize().testPersistence())
container2 = container.testSerialization()
pane2 = container2.getRoot()
container2.attachToDom()
expect(pane2).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
container3 = atom.deserializers.deserialize(container.serialize().testPersistence())
container3 = container.testSerialization()
pane3 = container3.getRoot()
container3.attachToDom()
expect(pane3).not.toMatchSelector(':has(:focus)')

View File

@@ -16,21 +16,17 @@ describe "Project", ->
afterEach ->
deserializedProject?.destroy()
it "destroys unretained buffers and does not include them in the serialized state", ->
it "does not include unretained buffers in the serialized state", ->
atom.project.bufferForPathSync('a')
expect(atom.project.getBuffers().length).toBe 1
atom.project.getState().serializeForPersistence()
deserializedProject = atom.project.testPersistence()
deserializedProject = atom.project.testSerialization()
expect(deserializedProject.getBuffers().length).toBe 0
expect(atom.project.getBuffers().length).toBe 0
it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", ->
atom.project.openSync('a')
expect(atom.project.getBuffers().length).toBe 1
atom.project.getState().serializeForPersistence()
deserializedProject = atom.project.testPersistence()
deserializedProject = atom.project.testSerialization()
expect(deserializedProject.getBuffers().length).toBe 1
deserializedProject.getBuffers()[0].destroy()

View File

@@ -7,7 +7,7 @@ path = require 'path'
{_, $, File, WorkspaceView, fs} = require 'atom'
Keymap = require '../src/keymap'
Config = require '../src/config'
{Point} = require 'telepath'
{Point} = require 'text-buffer'
Project = require '../src/project'
Editor = require '../src/editor'
EditorView = require '../src/editor-view'

View File

@@ -1,7 +1,6 @@
{_, fs} = require 'atom'
path = require 'path'
temp = require 'temp'
{Site} = require 'telepath'
TextBuffer = require '../src/text-buffer'
describe 'TextBuffer', ->

View File

@@ -93,7 +93,7 @@ describe "Window", ->
atom.unloadEditorWindow()
expect(atom.state.getObject('workspaceView')).toEqual workspaceViewState.toObject()
expect(atom.state.getObject('workspaceView')).toEqual workspaceViewState
expect(atom.state.getObject('syntax')).toEqual syntaxState
expect(atom.saveSync).toHaveBeenCalled()

View File

@@ -19,9 +19,11 @@ describe "WorkspaceView", ->
viewState = null
simulateReload = ->
state = atom.workspaceView.serialize().testPersistence()
workspaceState = atom.workspaceView.serialize()
projectState = atom.project.serialize()
atom.workspaceView.remove()
atom.workspaceView = WorkspaceView.deserialize(state)
atom.project = atom.deserializers.deserialize(projectState)
atom.workspaceView = WorkspaceView.deserialize(workspaceState)
atom.workspaceView.attachToDom()
describe "when the serialized WorkspaceView has an unsaved buffer", ->

View File

@@ -223,7 +223,7 @@ class Atom extends Model
# Private:
deserializeProject: ->
Project = require './project'
@project ?= new Project(path: @getLoadSettings().initialPath)
@project ?= @deserializers.deserialize(@project) ? new Project(path: @getLoadSettings().initialPath)
# Private:
deserializeWorkspaceView: ->
@@ -231,7 +231,7 @@ class Atom extends Model
@workspaceView = @deserializers.deserialize(@state.get('workspaceView'))
unless @workspaceView?
@workspaceView = new WorkspaceView()
@state.set('workspaceView', @workspaceView.getState())
@state.set('workspaceView', @workspaceView.serialize())
$(@workspaceViewParentSelector).append(@workspaceView)
# Private:

View File

@@ -1,5 +1,5 @@
{View} = require './space-pen-extensions'
{Point, Range} = require 'telepath'
{Point, Range} = require 'text-buffer'
_ = require 'underscore-plus'
### Internal ###

View File

@@ -1,4 +1,4 @@
{Point, Range} = require 'telepath'
{Point, Range} = require 'text-buffer'
{Emitter} = require 'emissary'
_ = require 'underscore-plus'

View File

@@ -32,6 +32,7 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
module.exports =
class Editor extends Model
Serializable.includeInto(this)
atom.deserializers.add(this)
@properties
scrollTop: 0

View File

@@ -1,39 +1,26 @@
Serializable = require 'nostalgia'
{$, View} = require './space-pen-extensions'
{TelepathicObject} = require 'telepath'
### Internal ###
module.exports =
class PaneAxis extends View
@acceptsDocuments: true
Serializable.includeInto(this)
@deserialize: (state) ->
new this(state)
initialize: ({children}={}) ->
@addChild(child) for child in children ? []
initialize: (args...) ->
if args[0] instanceof TelepathicObject
@state = args[0]
@state.get('children').each (child, index) =>
@addChild(atom.deserializers.deserialize(child), index, updateState: false)
else
@state = atom.create(deserializer: @className(), children: [])
@addChild(child) for child in args
serializeParams: ->
children: @children().views().map (child) -> child.serialize()
@state.get('children').on 'changed', ({index, insertedValues, removedValues, siteId}) =>
return if siteId is @state.siteId
for childState in removedValues
@removeChild(@children(":eq(#{index})").view(), updateState: false)
for childState, i in insertedValues
@addChild(atom.deserializers.deserialize(childState), index + i, updateState: false)
deserializeParams: (params) ->
params.children = params.children.map (childState) -> atom.deserializers.deserialize(childState)
params
addChild: (child, index=@children().length, options={}) ->
addChild: (child, index=@children().length) ->
@insertAt(index, child)
state = child.getState()
@state.get('children').insert(index, state) if options.updateState ? true
@getContainer()?.adjustPaneDimensions()
removeChild: (child, options={}) ->
options.updateState ?= true
removeChild: (child) ->
parent = @parent().view()
container = @getContainer()
childWasInactive = not child.isActive?()
@@ -54,11 +41,10 @@ class PaneAxis extends View
if parent.setRoot?
parent.setRoot(sibling, suppressPaneItemChangeEvents: childWasInactive)
else
parent.insertChildBefore(this, sibling, options)
parent.removeChild(this, options)
parent.insertChildBefore(this, sibling)
parent.removeChild(this)
sibling.focus() if siblingFocused
else
@state.get('children').remove(@indexOf(child)) if options.updateState
primitiveRemove(child)
container.adjustPaneDimensions()
@@ -66,7 +52,6 @@ class PaneAxis extends View
container.trigger 'pane:removed', [child] if child instanceof Pane
detachChild: (child) ->
@state.get('children').remove(@indexOf(child))
child.detach()
getContainer: ->
@@ -78,25 +63,11 @@ class PaneAxis extends View
getActivePane: ->
@find('.pane.active').view() ? @find('.pane:first').view()
insertChildBefore: (child, newChild, options={}) ->
insertChildBefore: (child, newChild) ->
newChild.insertBefore(child)
if options.updateState ? true
children = @state.get('children')
childIndex = children.indexOf(child.getState())
children.insert(childIndex, newChild.getState())
insertChildAfter: (child, newChild) ->
newChild.insertAfter(child)
children = @state.get('children')
childIndex = children.indexOf(child.getState())
children.insert(childIndex + 1, newChild.getState())
serialize: ->
state = @state.clone()
state.set('children', child.serialize() for child in @children().views())
state
getState: -> @state
horizontalChildUnits: ->
$(child).view().horizontalGridUnits() for child in @children()

View File

@@ -1,3 +1,4 @@
Serializable = require 'nostalgia'
{$, View} = require './space-pen-extensions'
Pane = require './pane'
{TelepathicObject} = require 'telepath'
@@ -5,33 +6,14 @@ Pane = require './pane'
# Private: Manages the list of panes within a {WorkspaceView}
module.exports =
class PaneContainer extends View
Serializable.includeInto(this)
atom.deserializers.add(this)
### Internal ###
@acceptsDocuments: true
@deserialize: (state) ->
container = new PaneContainer(state)
container.removeEmptyPanes()
container
@content: ->
@div class: 'panes'
initialize: (state) ->
if state instanceof TelepathicObject
@state = state
@setRoot(atom.deserializers.deserialize(@state.get('root')))
else
@state = atom.create(deserializer: 'PaneContainer')
@subscribe @state, 'changed', ({newValues, siteId}) =>
return if siteId is @state.siteId
if newValues.hasOwnProperty('root')
if rootState = newValues.root
@setRoot(deserialize(rootState))
else
@setRoot(null)
initialize: ({root}={}) ->
@setRoot(root)
@subscribe this, 'pane:attached', (event, pane) =>
@triggerActiveItemChange() if @getActivePane() is pane
@@ -48,12 +30,12 @@ class PaneContainer extends View
triggerActiveItemChange: ->
@trigger 'pane-container:active-pane-item-changed', [@getActivePaneItem()]
serialize: ->
state = @state.clone()
state.set('root', @getRoot()?.serialize())
state
serializeParams: ->
root: @getRoot()?.serialize()
getState: -> @state
deserializeParams: (params) ->
params.root = atom.deserializers.deserialize(params.root)
params
### Public ###
@@ -95,7 +77,6 @@ class PaneContainer extends View
if root?
@append(root)
root.makeActive?()
@state.set(root: root?.getState())
removeChild: (child) ->
throw new Error("Removing non-existant child") unless @getRoot() is child

View File

@@ -1,7 +1,8 @@
{dirname} = require 'path'
{$, View} = require './space-pen-extensions'
_ = require 'underscore-plus'
{TelepathicObject} = require 'telepath'
Serializable = require 'nostalgia'
PaneRow = require './pane-row'
PaneColumn = require './pane-column'
@@ -13,51 +14,31 @@ PaneColumn = require './pane-column'
# building a package that deals with switching between panes or tiems.
module.exports =
class Pane extends View
Serializable.includeInto(this)
@acceptsDocuments: true
@version: 1
@content: (wrappedView) ->
@div class: 'pane', tabindex: -1, =>
@div class: 'item-views', outlet: 'itemViews'
@deserialize: (state) ->
pane = new Pane(state)
pane.focusOnAttach = true if state.get('focused')
pane
activeItem: null
items: null
viewsByItem: null # Views without a setModel() method are stored here
# Private:
initialize: (args...) ->
@items = []
if args[0] instanceof TelepathicObject
@state = args[0]
@items = _.compact(@state.get('items').getValues())
item?.created?() for item in @getItems()
if args[0]?.items # deserializing
{@items, activeItemUri, @focusOnAttach} = args[0]
else
@items = args
@state = atom.create
deserializer: 'Pane'
items: @items
@items ?= []
@handleItemEvents(item) for item in @items
@subscribe @state.get('items'), 'changed', ({index, removedValues, insertedValues, siteId}) =>
return if siteId is @state.siteId
for item in removedValues
@removeItemAtIndex(index, updateState: false)
for item, i in insertedValues
@addItem(itemState, index + i, updateState: false)
@subscribe @state, 'changed', ({newValues, siteId}) =>
return if siteId is @state.siteId
if newValues.activeItemUri
@showItemForUri(newValues.activeItemUri)
@viewsByItem = new WeakMap()
activeItemUri = @state.get('activeItemUri')
unless activeItemUri? and @showItemForUri(activeItemUri)
@showItem(@items[0]) if @items.length > 0
@@ -84,6 +65,15 @@ class Pane extends View
@on 'focus', => @activeView?.focus(); false
@on 'focusin', => @makeActive()
deserializeParams: (params) ->
params.items = _.compact(params.items.map (itemState) -> atom.deserializers.deserialize(itemState))
params
serializeParams: ->
items: _.compact(@items.map (item) -> item.serialize?())
focusOnAttach: @is(':has(:focus)')
activeItemUri: @getActivePaneItem()?.getUri?()
# Private:
afterAttach: (onDom) ->
if @focusOnAttach and onDom
@@ -173,17 +163,14 @@ class Pane extends View
@activeView = view
@trigger 'pane:active-item-changed', [item]
@state.set('activeItemUri', item.getUri?())
# Private:
activeItemTitleChanged: =>
@trigger 'pane:active-item-title-changed'
# Public: Add an additional item at the specified index.
addItem: (item, index=@getActiveItemIndex()+1, options={}) ->
addItem: (item, index=@getActiveItemIndex() + 1) ->
return if _.include(@items, item)
@state.get('items').splice(index, 0, item) if options.updateState ? true
@items.splice(index, 0, item)
@trigger 'pane:item-added', [item, index]
@handleItemEvents(item)
@@ -191,8 +178,7 @@ class Pane extends View
handleItemEvents: (item) ->
if _.isFunction(item.on)
@subscribe item, 'destroyed', =>
@destroyItem(item) if @state.isAlive()
@subscribe item, 'destroyed', => @destroyItem(item)
# Public: Remove the currently active item.
destroyActiveItem: =>
@@ -268,17 +254,16 @@ class Pane extends View
@saveItem(item) for item in @getItems()
# Public:
removeItem: (item, options) ->
removeItem: (item) ->
index = @items.indexOf(item)
@removeItemAtIndex(index, options) if index >= 0
@removeItemAtIndex(index) if index >= 0
# Public: Just remove the item at the given index.
removeItemAtIndex: (index, options={}) ->
removeItemAtIndex: (index) ->
item = @items[index]
@activeItem.off? 'title-changed', @activeItemTitleChanged if item is @activeItem
@showNextItem() if item is @activeItem and @items.length > 1
_.remove(@items, item)
@state.get('items').splice(index, 1) if options.updateState ? true
@cleanupItemView(item)
@trigger 'pane:item-removed', [item, index]
@@ -287,14 +272,13 @@ class Pane extends View
oldIndex = @items.indexOf(item)
@items.splice(oldIndex, 1)
@items.splice(newIndex, 0, item)
@state.get('items').insert(newIndex, item)
@trigger 'pane:item-moved', [item, newIndex]
# Public: Moves the given item to another pane.
moveItemToPane: (item, pane, index) ->
@isMovingItem = true
pane.addItem(item, index)
@removeItem(item, updateState: false)
@removeItem(item)
@isMovingItem = false
# Public: Finds the first item that matches the given uri.
@@ -330,7 +314,7 @@ class Pane extends View
else if @isMovingItem and viewToRemove?.setModel
viewToRemove.setModel(null) # dont want to destroy the model, so set to null
@parent().view().removeChild(this, updateState: false)
@parent().view().removeChild(this)
# Private:
viewForItem: (item) ->
@@ -348,16 +332,6 @@ class Pane extends View
viewForActiveItem: ->
@viewForItem(@activeItem)
# Private:
serialize: ->
state = @state.clone()
state.set('items', @items)
state.set('focused', @is(':has(:focus)'))
state
# Private:
getState: -> @state
# Private:
adjustDimensions: -> # do nothing

View File

@@ -4,7 +4,9 @@ url = require 'url'
_ = require 'underscore-plus'
fs = require 'fs-plus'
Q = require 'q'
{Model} = require 'telepath'
{Model} = require 'reactionary'
{Emitter, Subscriber} = require 'emissary'
Serializable = require 'nostalgia'
TextBuffer = require './text-buffer'
Editor = require './editor'
@@ -18,9 +20,8 @@ Git = require './git'
# of directories and files that you can operate on.
module.exports =
class Project extends Model
@properties
path: null
atom.deserializers.add(this)
Serializable.includeInto(this)
# Public: Find the local path for the given repository URL.
@pathForRepositoryUrl: (repoUrl) ->
@@ -28,27 +29,23 @@ class Project extends Model
repoName = repoName.replace(/\.git$/, '')
path.join(atom.config.get('core.projectHome'), repoName)
constructor: ->
super
if @state?
@buffers = @state.get('buffers').map (state) -> atom.deserializers.deserialize(state)
# Private: Called by telepath.
created: ->
constructor: ({path, @buffers}={}) ->
@buffers ?= []
for buffer in @buffers
do (buffer) =>
buffer.once 'destroyed', => @removeBuffer(buffer) if @isAlive()
buffer.once 'destroyed', => @removeBuffer(buffer)
@openers = []
@editors = []
@setPath(@path)
@setPath(path)
# Private: Called by telepath.
willBePersisted: ->
@state.set('buffers', @buffers.map (buffer) -> buffer.serialize())
@destroyUnretainedBuffers()
serializeParams: ->
path: @path
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
deserializeParams: (params) ->
params.buffers = params.buffers.map (bufferState) -> atom.deserializers.deserialize(bufferState)
params
# Public: Register an opener for project files.
#
@@ -246,7 +243,7 @@ class Project extends Model
# Private:
addBufferAtIndex: (buffer, index, options={}) ->
@buffers.splice(index, 0, buffer)
buffer.once 'destroyed', => @removeBuffer(buffer) if @isAlive()
buffer.once 'destroyed', => @removeBuffer(buffer)
@emit 'buffer-created', buffer
buffer
@@ -345,7 +342,7 @@ class Project extends Model
# Private:
buildEditorForBuffer: (buffer, editorOptions) ->
editor = @create(new Editor(_.extend({buffer}, editorOptions)))
editor = new Editor(_.extend({buffer}, editorOptions))
@addEditor(editor)
editor

View File

@@ -4,7 +4,7 @@ Q = require 'q'
{$, $$, View} = require './space-pen-extensions'
_ = require 'underscore-plus'
fs = require 'fs-plus'
{TelepathicObject} = require 'telepath'
Serializable = require 'nostalgia'
EditorView = require './editor-view'
Pane = require './pane'
PaneColumn = require './pane-column'
@@ -38,9 +38,10 @@ Editor = require './editor'
#
module.exports =
class WorkspaceView extends View
Serializable.includeInto(this)
atom.deserializers.add(this, Pane, PaneRow, PaneColumn, EditorView)
@version: 1
@version: 2
@configDefaults:
ignoredNames: [".git", ".svn", ".DS_Store"]
@@ -50,31 +51,16 @@ class WorkspaceView extends View
projectHome: path.join(fs.getHomeDirectory(), 'github')
audioBeep: true
@acceptsDocuments: true
# Private:
@content: (state) ->
@content: ->
@div class: 'workspace', tabindex: -1, =>
@div class: 'horizontal', outlet: 'horizontal', =>
@div class: 'vertical', outlet: 'vertical', =>
@div class: 'panes', outlet: 'panes'
# Private:
@deserialize: (state) ->
new WorkspaceView(state)
# Private:
initialize: (state={}) ->
if state instanceof TelepathicObject
@state = state
panes = atom.deserializers.deserialize(state.get('panes'))
else
panes = new PaneContainer
@state = atom.create
deserializer: @constructor.name
version: @constructor.version
panes: panes.getState()
initialize: ({panes}={}) ->
panes ?= new PaneContainer
@panes.replaceWith(panes)
@panes = panes
@@ -131,14 +117,14 @@ class WorkspaceView extends View
@command 'core:save-as', => @saveActivePaneItemAs()
# Private:
serialize: ->
state = @state.clone()
state.set('panes', @panes.serialize())
state.set('fullScreen', atom.isFullScreen())
state
deserializeParams: (params) ->
params.panes = atom.deserializers.deserialize(params.panes)
params
# Private:
getState: -> @state
serializeParams: ->
panes: @panes.serialize()
fullScreen: atom.isFullScreen()
# Private:
handleFocus: (e) ->