diff --git a/spec/app/atom-spec.coffee b/spec/app/atom-spec.coffee index cdcb995cc..b597747be 100644 --- a/spec/app/atom-spec.coffee +++ b/spec/app/atom-spec.coffee @@ -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", -> diff --git a/spec/app/keymap-spec.coffee b/spec/app/keymap-spec.coffee index 21bc412dc..20a4cfc38 100644 --- a/spec/app/keymap-spec.coffee +++ b/spec/app/keymap-spec.coffee @@ -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' diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index 1022a249f..b1dc0b701 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -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 diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 1c166db8f..f595d51ec 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -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() diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 787e6aea9..77a39122e 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -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 diff --git a/src/app/atom.coffee b/src/app/atom.coffee index 82f77ea5d..de2bf680c 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -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] ? {}) diff --git a/src/app/config.coffee b/src/app/config.coffee index 6cbf66559..cf6f97b27 100644 --- a/src/app/config.coffee +++ b/src/app/config.coffee @@ -33,9 +33,8 @@ class Config load: -> @loadUserConfig() @requireUserInitScript() - atom.loadThemes() - atom.loadPackages() - keymap.loadUserKeymaps() + + loadUserConfig: -> if fs.exists(@configFilePath) diff --git a/src/app/keymap.coffee b/src/app/keymap.coffee index 676d33d44..74a493534 100644 --- a/src/app/keymap.coffee +++ b/src/app/keymap.coffee @@ -63,7 +63,7 @@ class Keymap keystrokeMap - handleKeyEvent: (event) -> + handleKeyEvent: (event) => event.keystrokes = @multiKeystrokeStringForEvent(event) isMultiKeystroke = @queuedKeystrokes? @queuedKeystrokes = null diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index 7af98bee5..bb7707069 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -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() diff --git a/src/app/window.coffee b/src/app/window.coffee index c177dcdb1..80e7463d7 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -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' diff --git a/src/packages/autocomplete/spec/autocomplete-spec.coffee b/src/packages/autocomplete/spec/autocomplete-spec.coffee index 76bd13018..9677deab2 100644 --- a/src/packages/autocomplete/spec/autocomplete-spec.coffee +++ b/src/packages/autocomplete/spec/autocomplete-spec.coffee @@ -48,6 +48,7 @@ describe "AutocompleteView", -> miniEditor = autocomplete.miniEditor afterEach -> + rootView.deactivate() editor?.remove() describe 'autocomplete:attach event', -> diff --git a/src/packages/autoflow/spec/autoflow-spec.coffee b/src/packages/autoflow/spec/autoflow-spec.coffee index 2f74691e9..c7d665075 100644 --- a/src/packages/autoflow/spec/autoflow-spec.coffee +++ b/src/packages/autoflow/spec/autoflow-spec.coffee @@ -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) diff --git a/src/packages/markdown-preview/spec/markdown-preview-spec.coffee b/src/packages/markdown-preview/spec/markdown-preview-spec.coffee index c1f259e91..ab5e2d341 100644 --- a/src/packages/markdown-preview/spec/markdown-preview-spec.coffee +++ b/src/packages/markdown-preview/spec/markdown-preview-spec.coffee @@ -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') diff --git a/src/packages/snippets/spec/snippets-spec.coffee b/src/packages/snippets/spec/snippets-spec.coffee index 0ccc9998a..6cbcbfae3 100644 --- a/src/packages/snippets/spec/snippets-spec.coffee +++ b/src/packages/snippets/spec/snippets-spec.coffee @@ -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") diff --git a/src/packages/tree-view/spec/tree-view-spec.coffee b/src/packages/tree-view/spec/tree-view-spec.coffee index 077ada940..bfb002ce9 100644 --- a/src/packages/tree-view/spec/tree-view-spec.coffee +++ b/src/packages/tree-view/spec/tree-view-spec.coffee @@ -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() diff --git a/src/window-bootstrap.coffee b/src/window-bootstrap.coffee index cca57c7d7..5483659a4 100644 --- a/src/window-bootstrap.coffee +++ b/src/window-bootstrap.coffee @@ -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}"