Make project a global and refactor startup process

This commit is contained in:
Nathan Sobo
2013-02-19 13:12:29 -07:00
committed by Corey Johnson & Nathan Sobo
parent 334a33cd74
commit 7f2747ead0
16 changed files with 126 additions and 128 deletions

View File

@@ -69,21 +69,19 @@ describe "the `atom` global", ->
beforeEach ->
spyOn(syntax, 'addGrammar')
it "terminates the worker when all packages have been loaded", ->
spyOn(Worker.prototype, 'terminate').andCallThrough()
it "aborts the worker when all packages have been loaded", ->
LoadTextMatePackagesTask = require 'load-text-mate-packages-task'
spyOn(LoadTextMatePackagesTask.prototype, 'abort').andCallThrough()
eventHandler = jasmine.createSpy('eventHandler')
syntax.on 'grammars-loaded', eventHandler
disabledPackages = config.get("core.disabledPackages")
disabledPackages.push('textmate-package.tmbundle')
disabledPackages.push('package-with-snippets')
config.set "core.disabledPackages", disabledPackages
config.get("core.disabledPackages").push('textmate-package.tmbundle', 'package-with-snippets')
atom.loadPackages()
waitsFor "all packages to load", 5000, -> eventHandler.callCount > 0
runs ->
expect(Worker.prototype.terminate).toHaveBeenCalled()
expect(Worker.prototype.terminate.calls.length).toBe 1
expect(LoadTextMatePackagesTask.prototype.abort).toHaveBeenCalled()
expect(LoadTextMatePackagesTask.prototype.abort.calls.length).toBe 1
describe "package lifecycle", ->
describe "activation", ->

View File

@@ -151,6 +151,8 @@ describe "Keymap", ->
expect(bazHandler).toHaveBeenCalled()
describe "when the event's target is the document body", ->
afterEach -> rootView.deactivate()
it "triggers the mapped event on the rootView", ->
rootView = new RootView
keymap.bindKeys 'body', 'x': 'foo'

View File

@@ -1,17 +1,19 @@
$ = require 'jquery'
fs = require 'fs'
Project = require 'project'
RootView = require 'root-view'
Buffer = require 'buffer'
Editor = require 'editor'
{View, $$} = require 'space-pen'
describe "RootView", ->
rootView = null
path = null
[rootView, pathToOpen] = []
beforeEach ->
path = require.resolve 'fixtures/dir/a'
rootView = new RootView(path)
project.destroy()
window.project = new Project(require.resolve('fixtures/dir'))
pathToOpen = project.resolve('a')
rootView = new RootView(pathToOpen)
rootView.enableKeymap()
rootView.focus()
@@ -21,34 +23,29 @@ describe "RootView", ->
describe ".initialize(pathToOpen)", ->
describe "when called with a pathToOpen", ->
describe "when pathToOpen references a file", ->
it "creates a project for the file's parent directory, then sets the title and opens the file in an editor", ->
expect(rootView.project.getPath()).toBe fs.directory(path)
it "opens the file at the given path and sets the window title", ->
expect(rootView.getEditors().length).toBe 1
expect(rootView.getEditors()[0]).toHaveClass 'active'
expect(rootView.getActiveEditor().getPath()).toBe path
expect(rootView.getActiveEditor().getPath()).toBe pathToOpen
expect(rootView.getActiveEditor().editSessions.length).toBe 1
expect(rootView.getTitle()).toBe "#{fs.base(path)} #{rootView.project.getPath()}"
expect(rootView.getTitle()).toBe "#{fs.base(pathToOpen)} #{project.getPath()}"
describe "when pathToOpen references a directory", ->
beforeEach ->
rootView.remove()
it "creates a project for the directory and sets the title, but does not open an editor", ->
path = require.resolve 'fixtures/dir'
rootView = new RootView(path)
it "does not open an editor", ->
pathToOpen = project.getPath()
rootView = new RootView(pathToOpen)
rootView.focus()
expect(rootView.project.getPath()).toBe path
expect(rootView.project.getPath()).toBe pathToOpen
expect(rootView.getEditors().length).toBe 0
expect(rootView.getTitle()).toBe rootView.project.getPath()
describe "when called with no pathToOpen", ->
it "opens an empty buffer", ->
rootView.remove()
rootView = new RootView
expect(rootView.getEditors().length).toBe 1
expect(rootView.getEditors()[0].getText()).toEqual ""
expect(rootView.getTitle()).toBe 'untitled'
expect(rootView.getTitle()).toBe "untitled #{project.getPath()}"
describe ".deactivate()", ->
it "deactivates all packages", ->
@@ -65,7 +62,6 @@ describe "RootView", ->
buffer = null
beforeEach ->
rootView.remove()
rootView = new RootView
rootView.open()
editor1 = rootView.getActiveEditor()
@@ -75,16 +71,14 @@ describe "RootView", ->
it "constructs the view with the same panes", ->
rootView = RootView.deserialize(viewState)
expect(rootView.project.getPath()?).toBeFalsy()
rootView.focus()
expect(rootView.getEditors().length).toBe 2
expect(rootView.getActiveEditor().getText()).toBe buffer.getText()
expect(rootView.getTitle()).toBe 'untitled'
expect(rootView.getTitle()).toBe "untitled #{project.getPath()}"
describe "when the serialized RootView has a project", ->
beforeEach ->
path = require.resolve 'fixtures'
rootView.remove()
rootView = new RootView(path)
project.setPath(require.resolve('fixtures'))
describe "when there are open editors", ->
beforeEach ->
@@ -92,6 +86,7 @@ describe "RootView", ->
editor1 = rootView.getActiveEditor()
editor2 = editor1.splitRight()
editor3 = editor2.splitRight()
editor4 = editor2.splitDown()
editor2.edit(rootView.project.buildEditSessionForPath('dir/b'))
editor3.edit(rootView.project.buildEditSessionForPath('sample.js'))
@@ -136,15 +131,16 @@ describe "RootView", ->
describe "where there are no open editors", ->
beforeEach ->
rootView.attachToDom()
rootView.deactivate()
rootView = new RootView(project.getPath())
expect(rootView.getEditors().length).toBe 0
viewState = rootView.serialize()
rootView.remove()
it "constructs the view with no open editors", ->
rootView = RootView.deserialize(viewState)
rootView.attachToDom()
expect(rootView.getEditors().length).toBe 0
rootView = RootView.deserialize(viewState)
rootView.attachToDom()
expect(rootView.getEditors().length).toBe 0
describe "when a pane's wrapped view cannot be deserialized", ->
it "renders an empty pane", ->
@@ -448,7 +444,7 @@ describe "RootView", ->
expect(Object.keys(keybindings).length).toBe 2
expect(keybindings["meta-a"]).toEqual "test-event-a"
describe "when the focused editor changes", ->
describe "when the path of the active editor changes", ->
it "changes the title and emits an root-view:active-path-changed event", ->
pathChangeHandler = jasmine.createSpy 'pathChangeHandler'
rootView.on 'root-view:active-path-changed', pathChangeHandler
@@ -468,8 +464,8 @@ describe "RootView", ->
expect(pathChangeHandler).not.toHaveBeenCalled()
expect(rootView.getTitle()).toBe "#{fs.base(editor2.getPath())} #{rootView.project.getPath()}"
it "creates a project if there isn't one yet and the buffer was previously unsaved", ->
rootView.remove()
it "sets the project path to the directory of the editor if it was previously unassigned", ->
project.setPath(undefined)
rootView = new RootView
rootView.open()
expect(rootView.project.getPath()?).toBeFalsy()
@@ -624,12 +620,12 @@ describe "RootView", ->
describe ".saveAll()", ->
it "saves all open editors", ->
rootView.remove()
project.setPath('/tmp')
file1 = '/tmp/atom-temp1.txt'
file2 = '/tmp/atom-temp2.txt'
fs.write(file1, "file1")
fs.write(file2, "file2")
rootView = new RootView(file1)
rootView.open(file1)
editor1 = rootView.getActiveEditor()
buffer1 = editor1.activeEditSession.buffer

View File

@@ -5,12 +5,13 @@ describe "Window", ->
[rootView] = []
beforeEach ->
window.setUpEventHandlers()
window.attachRootView(require.resolve('fixtures'))
window.handleWindowEvents()
spyOn(atom, 'getPathToOpen').andReturn(project.getPath())
window.buildProjectAndRootView()
rootView = window.rootView
afterEach ->
window.shutdown()
window.stopApplication()
atom.setRootViewStateForPath(rootView.project.getPath(), null)
$(window).off 'beforeunload'
@@ -86,12 +87,18 @@ describe "Window", ->
removeStylesheet(cssPath)
expect($(document.body).css('font-weight')).not.toBe("bold")
describe "before the window is unloaded", ->
it "saves the serialized state of the root view to the atom object so it can be rehydrated after reload", ->
expect(atom.getRootViewStateForPath(window.rootView.project.getPath())).toBeUndefined()
expectedState = JSON.parse(JSON.stringify(window.rootView.serialize())) # JSON.stringify removes keys with undefined values
$(window).trigger 'beforeunload'
expect(atom.getRootViewStateForPath(rootView.project.getPath())).toEqual expectedState
describe "stopApplication()", ->
it "saves the serialized state of the project and root view to the atom object so it can be rehydrated after reload", ->
expect(atom.getRootViewStateForPath(rootView.project.getPath())).toBeUndefined()
# JSON.stringify removes keys with undefined values
rootViewState = JSON.parse(JSON.stringify(rootView.serialize()))
projectState = JSON.parse(JSON.stringify(project.serialize()))
stopApplication()
expect(atom.getRootViewStateForPath(project.getPath())).toEqual
project: projectState
rootView: rootViewState
it "unsubscribes from all buffers", ->
rootView.open('sample.js')
@@ -99,15 +106,7 @@ describe "Window", ->
editor2 = editor1.splitRight()
expect(window.rootView.getEditors().length).toBe 2
$(window).trigger 'beforeunload'
stopApplication()
expect(editor1.getBuffer().subscriptionCount()).toBe 0
describe ".shutdown()", ->
it "only deactivates the RootView the first time it is called", ->
deactivateSpy = spyOn(rootView, "deactivate").andCallThrough()
window.shutdown()
expect(rootView.deactivate).toHaveBeenCalled()
deactivateSpy.reset()
window.shutdown()
expect(rootView.deactivate).not.toHaveBeenCalled()

View File

@@ -15,11 +15,13 @@ RootView = require 'root-view'
requireStylesheet "jasmine.css"
fixturePackagesPath = require.resolve('fixtures/packages')
require.paths.unshift(fixturePackagesPath)
keymap.loadBundledKeymaps()
[bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []
beforeEach ->
jQuery.fx.off = true
window.fixturesProject = new Project(require.resolve('fixtures'))
window.project = fixturesProject
window.resetTimeouts()
atom.atomPackageStates = {}
atom.loadedPackages = []
@@ -54,13 +56,14 @@ beforeEach ->
afterEach ->
keymap.bindingSets = bindingSetsToRestore
keymap.bindingSetsByFirstKeystrokeToRestore = bindingSetsByFirstKeystrokeToRestore
rootView?.deactivate()
delete window.rootView if window.rootView
project.destroy()
$('#jasmine-content').empty()
window.fixturesProject.destroy()
ensureNoPathSubscriptions()
waits(0) # yield to ui thread to make screen update more frequently
window.keymap.bindKeys '*', 'meta-w': 'close'
# window.keymap.bindKeys '*', 'meta-w': 'close'
$(document).on 'close', -> window.close()
$(document).on 'toggle-dev-tools', (e) ->
atom.toggleDevTools() if $('#root-view').length is 0

View File

@@ -16,6 +16,9 @@ _.extend atom,
activatedAtomPackages: []
atomPackageStates: {}
getPathToOpen: ->
@getWindowState('pathToOpen') ? window.location.params.pathToOpen
activateAtomPackage: (pack) ->
@activatedAtomPackages.push(pack)
pack.packageMain.activate(@atomPackageStates[pack.name] ? {})

View File

@@ -33,9 +33,8 @@ class Config
load: ->
@loadUserConfig()
@requireUserInitScript()
atom.loadThemes()
atom.loadPackages()
keymap.loadUserKeymaps()
loadUserConfig: ->
if fs.exists(@configFilePath)

View File

@@ -63,7 +63,7 @@ class Keymap
keystrokeMap
handleKeyEvent: (event) ->
handleKeyEvent: (event) =>
event.keystrokes = @multiKeystrokeStringForEvent(event)
isMultiKeystroke = @queuedKeystrokes?
@queuedKeystrokes = null

View File

@@ -25,15 +25,9 @@ class RootView extends View
@div id: 'vertical', outlet: 'vertical', =>
@div id: 'panes', outlet: 'panes'
@deserialize: ({ projectState, panesViewState, packageStates, projectPath }) ->
if projectState
projectOrPathToOpen = Project.deserialize(projectState)
else
projectOrPathToOpen = projectPath # This will migrate people over to the new project serialization scheme. It should be removed eventually.
@deserialize: ({ panesViewState, packageStates, projectPath }) ->
atom.atomPackageStates = packageStates ? {}
rootView = new RootView(projectOrPathToOpen, suppressOpen: true)
rootView = new RootView(null, suppressOpen: true)
rootView.setRootPane(deserialize(panesViewState)) if panesViewState
rootView
@@ -44,23 +38,23 @@ class RootView extends View
window.rootView = this
@handleEvents()
@project = window.project
if not projectOrPathToOpen or _.isString(projectOrPathToOpen)
pathToOpen = projectOrPathToOpen
@project = new Project(projectOrPathToOpen)
else
@project = projectOrPathToOpen
pathToOpen = @project?.getPath()
@pathToOpenIsFile = pathToOpen and fs.isFile(pathToOpen)
config.load()
if pathToOpen
@open(pathToOpen) if @pathToOpenIsFile and not suppressOpen
else
@open()
unless suppressOpen
if pathToOpen
@open(pathToOpen) if @pathToOpenIsFile
else
@open()
serialize: ->
projectState: @project?.serialize()
panesViewState: @panes.children().view()?.serialize()
packageStates: atom.serializeAtomPackages()
@@ -113,7 +107,6 @@ class RootView extends View
@focus() if onDom
deactivate: ->
atom.setRootViewStateForPath(@project.getPath(), @serialize())
atom.deactivateAtomPackages()
@remove()

View File

@@ -3,9 +3,6 @@
fs = require 'fs'
$ = require 'jquery'
Config = require 'config'
Syntax = require 'syntax'
Pasteboard = require 'pasteboard'
require 'jquery-extensions'
require 'underscore-extensions'
require 'space-pen-extensions'
@@ -20,15 +17,22 @@ windowAdditions =
# This method runs when the file is required. Any code here will run
# in all environments: spec, benchmark, and application
startup: ->
@config = new Config
@syntax = new Syntax
@setUpKeymap()
@pasteboard = new Pasteboard
@setUpEventHandlers()
setUpEnvironment: ->
Config = require 'config'
Syntax = require 'syntax'
Pasteboard = require 'pasteboard'
Keymap = require 'keymap'
window.config = new Config
window.syntax = new Syntax
window.pasteboard = new Pasteboard
window.keymap = new Keymap()
$(document).on 'keydown', keymap.handleKeyEvent
keymap.bindDefaultKeys()
setUpEventHandlers: ->
$(window).on 'core:close', => @close()
handleWindowEvents: ->
$(window).command 'window:close', => @close()
$(window).command 'window:toggle-full-screen', => atom.toggleFullScreen()
$(window).on 'focus', -> $("body").removeClass('is-blurred')
@@ -37,37 +41,36 @@ windowAdditions =
# This method is intended only to be run when starting a normal application
# Note: RootView assigns itself on window on initialization so that
# window.rootView is available when loading user configuration
attachRootView: (pathToOpen) ->
RootView = require 'root-view'
if pathState = atom.getRootViewStateForPath(pathToOpen)
RootView.deserialize(pathState)
else
new RootView(pathToOpen)
$(@rootViewParentSelector).append(@rootView)
startApplication: ->
config.load()
buildProjectAndRootView()
keymap.loadBundledKeymaps()
keymap.loadUserKeymaps()
atom.loadThemes()
atom.loadPackages()
$(window).on 'beforeunload', -> stopApplication(); false
$(window).focus()
$(window).on 'beforeunload', =>
@shutdown()
false
shutdown: ->
if @rootView
atom.setWindowState('pathToOpen', @rootView.project.getPath())
@rootView.deactivate()
@rootView = null
$(window).off('focus')
$(window).off('blur')
$(window).off('before')
buildProjectAndRootView: ->
RootView = require 'root-view'
Project = require 'project'
setUpKeymap: ->
Keymap = require 'keymap'
if windowState = atom.getRootViewStateForPath(atom.getPathToOpen()) and windowState?.project?
window.project = deserialize(windowState.project)
window.rootView = deserialize(windowState.rootView)
else
window.project = new Project(atom.getPathToOpen())
window.rootView = new RootView(atom.getPathToOpen())
$(rootViewParentSelector).append(rootView)
@keymap = new Keymap()
@keymap.bindDefaultKeys()
@keymap.loadBundledKeymaps()
@_handleKeyEvent = (e) => @keymap.handleKeyEvent(e)
$(document).on 'keydown', @_handleKeyEvent
stopApplication: ->
atom.setWindowState('pathToOpen', rootView.project.getPath())
atom.setRootViewStateForPath project.getPath(),
project: project.serialize()
rootView: rootView.serialize()
rootView.deactivate()
project.destroy()
$(window).off('focus blur before')
stylesheetElementForId: (id) ->
$("head style[id='#{id}']")
@@ -121,7 +124,7 @@ windowAdditions =
value
window[key] = value for key, value of windowAdditions
window.startup()
window.setUpEnvironment()
requireStylesheet 'reset.css'
requireStylesheet 'atom.css'

View File

@@ -48,6 +48,7 @@ describe "AutocompleteView", ->
miniEditor = autocomplete.miniEditor
afterEach ->
rootView.deactivate()
editor?.remove()
describe 'autocomplete:attach event', ->

View File

@@ -4,7 +4,7 @@ describe "Autoflow package", ->
editor = null
beforeEach ->
rootView = new RootView
new RootView
window.loadPackage 'autoflow'
editor = rootView.getActiveEditor()
config.set('editor.preferredLineLength', 30)

View File

@@ -5,7 +5,8 @@ _ = require 'underscore'
describe "MarkdownPreview", ->
beforeEach ->
rootView = new RootView(require.resolve('fixtures/markdown'))
project.setPath(project.resolve('markdown'))
rootView = new RootView(project.getPath())
window.loadPackage("markdown-preview")
spyOn(MarkdownPreview.prototype, 'loadHtml')

View File

@@ -10,7 +10,7 @@ Package = require 'package'
describe "Snippets extension", ->
[buffer, editor, editSession] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
new RootView(project.resolve('sample.js'))
spyOn(LoadSnippetsTask.prototype, 'start')
packageWithSnippets = window.loadPackage("package-with-snippets")

View File

@@ -6,11 +6,11 @@ Directory = require 'directory'
fs = require 'fs'
describe "TreeView", ->
[project, treeView, sampleJs, sampleTxt] = []
[treeView, sampleJs, sampleTxt] = []
beforeEach ->
new RootView(require.resolve('fixtures/tree-view'))
project = rootView.project
project.setPath(project.resolve('tree-view'))
new RootView(project.getPath())
window.loadPackage("tree-view")
rootView.trigger 'tree-view:toggle'
@@ -48,6 +48,7 @@ describe "TreeView", ->
describe "when the project has no path", ->
beforeEach ->
project.setPath(undefined)
rootView.deactivate()
new RootView()
treeView = window.loadPackage("tree-view").packageMain.createView()
@@ -605,8 +606,8 @@ describe "TreeView", ->
fs.makeDirectory(dirPath)
fs.write(filePath, "doesn't matter")
project.setPath(rootDirPath)
new RootView(rootDirPath)
project = rootView.project
window.loadPackage('tree-view')
rootView.trigger 'tree-view:toggle'
treeView = rootView.find(".tree-view").view()

View File

@@ -3,7 +3,6 @@ date = new Date().getTime()
require 'atom'
require 'window'
pathToOpen = atom.getWindowState('pathToOpen') ? window.location.params.pathToOpen
window.attachRootView(pathToOpen)
window.startApplication()
atom.show()
console.log "Load time: #{new Date().getTime() - date}"