From e89a2255cf76d55402f80a03277519e745a63703 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 18 Apr 2012 11:01:30 -0600 Subject: [PATCH] Tear down editors and unsubscribe from buffers on window unload to prevent exceptions when typing after reload --- benchmark/benchmark-suite.coffee | 2 + spec/app/window-spec.coffee | 64 +++++++++++++++++--------------- src/app/root-view.coffee | 6 ++- src/app/window.coffee | 6 ++- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/benchmark/benchmark-suite.coffee b/benchmark/benchmark-suite.coffee index 73dc41345..38dea60f5 100644 --- a/benchmark/benchmark-suite.coffee +++ b/benchmark/benchmark-suite.coffee @@ -1,6 +1,7 @@ Buffer = require 'buffer' fs = require 'fs' require 'benchmark-helper' +$ = require 'jquery' describe "editor.", -> editor = null @@ -11,6 +12,7 @@ describe "editor.", -> editor = rootView.activeEditor() afterEach -> + $(window).off 'beforeunload' window.shutdown() describe "empty-file.", -> diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 5e49405e2..0d63e58cf 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -2,42 +2,48 @@ $ = require 'jquery' fs = require 'fs' describe "Window", -> - describe "keybindings", -> - beforeEach -> - window.startup() + beforeEach -> + window.startup() - afterEach -> - window.shutdown() + afterEach -> + window.shutdown() + delete atom.rootViewStates[$windowNumber] + $(window).off 'beforeunload' - describe ".close()", -> - it "is triggered by the 'close' event", -> - spyOn window, 'close' - $(window).trigger 'close' - expect(window.close).toHaveBeenCalled() + describe ".close()", -> + it "is triggered by the 'close' event", -> + spyOn window, 'close' + $(window).trigger 'close' + expect(window.close).toHaveBeenCalled() - describe "requireStylesheet(path)", -> - it "synchronously loads the stylesheet at the given path and installs a style tag for it in the head", -> - $('head style').remove() - expect($('head style').length).toBe 0 - requireStylesheet('atom.css') - expect($('head style').length).toBe 1 + describe "requireStylesheet(path)", -> + it "synchronously loads the stylesheet at the given path and installs a style tag for it in the head", -> + $('head style').remove() + expect($('head style').length).toBe 0 + requireStylesheet('atom.css') + expect($('head style').length).toBe 1 - styleElt = $('head style') + styleElt = $('head style') - fullPath = require.resolve('atom.css') - expect(styleElt.attr('path')).toBe fullPath - expect(styleElt.text()).toBe fs.read(fullPath) + fullPath = require.resolve('atom.css') + expect(styleElt.attr('path')).toBe fullPath + expect(styleElt.text()).toBe fs.read(fullPath) - requireStylesheet('atom.css') - expect($('head style').length).toBe 1 + requireStylesheet('atom.css') + expect($('head style').length).toBe 1 - describe "before the window is unloaded", -> - afterEach -> - delete atom.rootViewStates[$windowNumber] + 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.rootViewStates[$windowNumber]).toBeUndefined() + expectedState = window.rootView.serialize() + $(window).trigger 'beforeunload' + expect(atom.rootViewStates[$windowNumber]).toEqual expectedState - it "saves the serialized state of the root view to the atom object so it can be rehydrated after reload", -> - expect(atom.rootViewStates[$windowNumber]).toBeUndefined() - $(window).trigger 'beforeunload' - expect(atom.rootViewStates[$windowNumber]).toEqual window.rootView.serialize() + it "unsubscribes from all buffers", -> + editor1 = rootView.activeEditor() + editor2 = editor1.splitRight() + expect(window.rootView.editors().length).toBe 2 + $(window).trigger 'beforeunload' + expect(editor1.buffer.subscriptionCount()).toBe 1 # buffer has a self-subscription for the undo manager diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index 849e5cb29..89f420ac7 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -52,7 +52,7 @@ class RootView extends View panesViewState: @serializePanes() serializePanes: () -> - @panes.children().view().serialize() + @panes.children().view()?.serialize() deserializePanes: (panesViewState) -> @panes.append @deserializeView(panesViewState) @@ -122,3 +122,7 @@ class RootView extends View selected: (relativePath) => @open(relativePath) @append @fileFinder @fileFinder.editor.focus() + + remove: -> + editor.remove() for editor in @editors() + super diff --git a/src/app/window.coffee b/src/app/window.coffee index 32c0a9812..7d2fc0d14 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -24,11 +24,14 @@ windowAdditions = @attachRootView(path) @loadUserConfiguration() $(window).on 'close', => @close() - $(window).on 'beforeunload', => @saveRootViewState() + $(window).on 'beforeunload', => + @shutdown() + false $(window).focus() atom.windowOpened this shutdown: -> + @saveRootViewState() @rootView.remove() $(window).unbind('focus') $(window).unbind('blur') @@ -38,6 +41,7 @@ windowAdditions = attachRootView: (pathToOpen) -> rootViewState = atom.rootViewStates[$windowNumber] @rootView = if rootViewState + console.log "RootView deserialize", rootViewState RootView.deserialize(rootViewState) else new RootView {pathToOpen}