From a8692f19847153ff4dc1f1256a9d6d779c423f4a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 26 Jan 2016 22:46:17 -0700 Subject: [PATCH 01/66] Extract serialize functionality from ::deactivatePackage. Tests WIP --- spec/package-manager-spec.coffee | 79 +++++++++++++++++--------------- src/package-manager.coffee | 11 ++++- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 46d1d11ee..5a19a10aa 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -444,20 +444,18 @@ describe "PackageManager", -> runs -> expect(console.warn).not.toHaveBeenCalled() - it "passes the activate method the package's previously serialized state if it exists", -> - pack = null + fit "passes the activate method the package's previously serialized state if it exists", -> + pack = atom.packages.loadPackage("package-with-serialization") waitsForPromise -> - atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p - + pack.activate() # require main module runs -> - expect(pack.mainModule.someNumber).not.toBe 77 - pack.mainModule.someNumber = 77 + atom.packages.setPackageState("package-with-serialization", {someNumber: 77}) atom.packages.deactivatePackage("package-with-serialization") spyOn(pack.mainModule, 'activate').andCallThrough() - waitsForPromise -> - atom.packages.activatePackage("package-with-serialization") - runs -> - expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77}) + waitsForPromise -> + atom.packages.activatePackage("package-with-serialization") + runs -> + expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77}) it "invokes ::onDidActivatePackage listeners with the activated package", -> activatedPackage = null @@ -821,6 +819,40 @@ describe "PackageManager", -> expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true expect(addErrorHandler.callCount).toBe 0 + describe "::serialize", -> + # TODO + + describe "::serializePackage(pack)", -> + # afterEach -> + # atom.packages.unloadPackages() + + fit "does not serialize packages that have not been activated called on their main module", -> + spyOn(console, 'warn') + badPack = null + waitsForPromise -> + atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p + + runs -> + spyOn(badPack.mainModule, 'serialize').andCallThrough() + + atom.packages.serializePackage(badPack) + expect(badPack.mainModule.serialize).not.toHaveBeenCalled() + + fit "absorbs exceptions that are thrown by the package module's serialize method", -> + spyOn(console, 'error') + + waitsForPromise -> + atom.packages.activatePackage('package-with-serialize-error') + + waitsForPromise -> + atom.packages.activatePackage('package-with-serialization') + + runs -> + atom.packages.deactivatePackages() + expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() + expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1 + expect(console.error).toHaveBeenCalled() + describe "::deactivatePackage(id)", -> afterEach -> atom.packages.unloadPackages() @@ -852,33 +884,6 @@ describe "PackageManager", -> expect(badPack.mainModule.deactivate).not.toHaveBeenCalled() expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy() - it "does not serialize packages that have not been activated called on their main module", -> - spyOn(console, 'warn') - badPack = null - waitsForPromise -> - atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p - - runs -> - spyOn(badPack.mainModule, 'serialize').andCallThrough() - - atom.packages.deactivatePackage("package-that-throws-on-activate") - expect(badPack.mainModule.serialize).not.toHaveBeenCalled() - - it "absorbs exceptions that are thrown by the package module's serialize method", -> - spyOn(console, 'error') - - waitsForPromise -> - atom.packages.activatePackage('package-with-serialize-error') - - waitsForPromise -> - atom.packages.activatePackage('package-with-serialization') - - runs -> - atom.packages.deactivatePackages() - expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() - expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1 - expect(console.error).toHaveBeenCalled() - it "absorbs exceptions that are thrown by the package module's deactivate method", -> spyOn(console, 'error') diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 1ecdc5448..3a3a74711 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -467,6 +467,15 @@ class PackageManager return unless hook? and _.isString(hook) and hook.length > 0 @activationHookEmitter.on(hook, callback) + serialize: -> + for pack in @getLoadedPackages() + @serializePackage(pack) + @packageStates + + serializePackage: (pack) -> + if @isPackageActive(pack.name) + @setPackageState(pack.name, state) if state = pack.serialize?() + # Deactivate all packages deactivatePackages: -> @config.transact => @@ -478,8 +487,6 @@ class PackageManager # Deactivate the package with the given name deactivatePackage: (name) -> pack = @getLoadedPackage(name) - if @isPackageActive(name) - @setPackageState(pack.name, state) if state = pack.serialize?() pack.deactivate() delete @activePackages[pack.name] delete @activatingPackages[pack.name] From 82d584bac65b163177a5236824dfa061171cf07e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 26 Jan 2016 22:52:30 -0700 Subject: [PATCH 02/66] Serialize in saveStateSync. Separate deserialization from deactivation. --- src/atom-environment.coffee | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index de52fe55c..110f51acb 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -636,16 +636,19 @@ class AtomEnvironment extends Model @openInitialEmptyEditorIfNecessary() + serialize: -> + @state.project = @project.serialize() + @state.workspace = @workspace.serialize() + @state.packageStates = @packages.serialize() + @state.grammars = {grammarOverridesByPath: @grammars.grammarOverridesByPath} + @state.fullScreen = @isFullScreen() + unloadEditorWindow: -> return if not @project @storeWindowBackground() - @state.grammars = {grammarOverridesByPath: @grammars.grammarOverridesByPath} - @state.project = @project.serialize() - @state.workspace = @workspace.serialize() + @serialize() @packages.deactivatePackages() - @state.packageStates = @packages.packageStates - @state.fullScreen = @isFullScreen() @saveStateSync() @saveBlobStoreSync() @@ -782,6 +785,7 @@ class AtomEnvironment extends Model saveStateSync: -> return unless @enablePersistence + @serialize() if storageKey = @getStateKey(@project?.getPaths()) @getStorageFolder().store(storageKey, @state) From 39cb52c2241a83512e2122734cb5655ededee20a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 11:13:29 -0700 Subject: [PATCH 03/66] Fix tests for serialization --- spec/package-manager-spec.coffee | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 5a19a10aa..969215799 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -444,7 +444,7 @@ describe "PackageManager", -> runs -> expect(console.warn).not.toHaveBeenCalled() - fit "passes the activate method the package's previously serialized state if it exists", -> + it "passes the activate method the package's previously serialized state if it exists", -> pack = atom.packages.loadPackage("package-with-serialization") waitsForPromise -> pack.activate() # require main module @@ -819,14 +819,9 @@ describe "PackageManager", -> expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true expect(addErrorHandler.callCount).toBe 0 - describe "::serialize", -> - # TODO + describe "serialization", -> - describe "::serializePackage(pack)", -> - # afterEach -> - # atom.packages.unloadPackages() - - fit "does not serialize packages that have not been activated called on their main module", -> + it "does not serialize packages that have not been activated called on their main module", -> spyOn(console, 'warn') badPack = null waitsForPromise -> @@ -838,7 +833,7 @@ describe "PackageManager", -> atom.packages.serializePackage(badPack) expect(badPack.mainModule.serialize).not.toHaveBeenCalled() - fit "absorbs exceptions that are thrown by the package module's serialize method", -> + it "absorbs exceptions that are thrown by the package module's serialize method", -> spyOn(console, 'error') waitsForPromise -> @@ -848,7 +843,7 @@ describe "PackageManager", -> atom.packages.activatePackage('package-with-serialization') runs -> - atom.packages.deactivatePackages() + atom.packages.serialize() expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1 expect(console.error).toHaveBeenCalled() From df83078d741164a32840396527911a0bb2e10496 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 11:15:02 -0700 Subject: [PATCH 04/66] Save state on mousedown or keypress events (debounce 1s). Tests WIP --- spec/atom-environment-spec.coffee | 13 +++++++++++++ src/atom-environment.coffee | 3 +++ 2 files changed, 16 insertions(+) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index b5b975112..938b0eb31 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -174,6 +174,19 @@ describe "AtomEnvironment", -> atom.loadStateSync() expect(atom.state.stuff).toBe("cool") + it "saves state on keypress and mousedown events", -> + spyOn(atom, 'saveStateSync') + + keypress = new KeyboardEvent('keypress') + atom.document.dispatchEvent(keypress) + advanceClock 1100 + expect(atom.saveStateSync).toHaveBeenCalled() + + mousedown = new MouseEvent('mousedown') + atom.document.dispatchEvent(mousedown) + advanceClock 1100 + expect(atom.saveStateSync).toHaveBeenCalled() + describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> beforeEach -> diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 110f51acb..3e1c28240 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -119,6 +119,9 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params + @document.addEventListener('mousedown', _.debounce(@saveStateSync.bind(this), 1000), true) + @document.addEventListener('keypress', _.debounce(@saveStateSync.bind(this), 1000), true) + @state = {version: @constructor.version} @loadTime = null From e09c7a99111c1f95da24281dd40aec19b4032be4 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 14:58:19 -0700 Subject: [PATCH 05/66] =?UTF-8?q?Avoid=20binding=20method=20before=20it?= =?UTF-8?q?=E2=80=99s=20spied=20upon=20when=20debouncing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom-environment.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 3e1c28240..d13937bc6 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -119,8 +119,9 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params - @document.addEventListener('mousedown', _.debounce(@saveStateSync.bind(this), 1000), true) - @document.addEventListener('keypress', _.debounce(@saveStateSync.bind(this), 1000), true) + debouncedSaveStateSync = _.debounce((=> @saveStateSync()), 1000) + @document.addEventListener('mousedown', debouncedSaveStateSync, true) + @document.addEventListener('keypress', debouncedSaveStateSync, true) @state = {version: @constructor.version} From 8d55bbcdeadc41b07a1e5e710e45b4a939c399eb Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 15:10:35 -0700 Subject: [PATCH 06/66] :art: clean up test --- spec/package-manager-spec.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 969215799..8710927df 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -819,9 +819,8 @@ describe "PackageManager", -> expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true expect(addErrorHandler.callCount).toBe 0 - describe "serialization", -> - - it "does not serialize packages that have not been activated called on their main module", -> + describe "::serialize", -> + it "does not serialize packages that threw an error during activation", -> spyOn(console, 'warn') badPack = null waitsForPromise -> @@ -830,7 +829,7 @@ describe "PackageManager", -> runs -> spyOn(badPack.mainModule, 'serialize').andCallThrough() - atom.packages.serializePackage(badPack) + atom.packages.serialize() expect(badPack.mainModule.serialize).not.toHaveBeenCalled() it "absorbs exceptions that are thrown by the package module's serialize method", -> From 126baafda39d3d6a5a0f259ccb81864c069e176c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 15:11:40 -0700 Subject: [PATCH 07/66] Assign debounce interval to property --- spec/atom-environment-spec.coffee | 4 ++-- src/atom-environment.coffee | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 938b0eb31..4621886dc 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -179,12 +179,12 @@ describe "AtomEnvironment", -> keypress = new KeyboardEvent('keypress') atom.document.dispatchEvent(keypress) - advanceClock 1100 + advanceClock atom.saveStateDebounceInterval expect(atom.saveStateSync).toHaveBeenCalled() mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) - advanceClock 1100 + advanceClock atom.saveStateDebounceInterval expect(atom.saveStateSync).toHaveBeenCalled() describe "openInitialEmptyEditorIfNecessary", -> diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index d13937bc6..cabd1896b 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -111,6 +111,8 @@ class AtomEnvironment extends Model # Public: A {Workspace} instance workspace: null + saveStateDebounceInterval: 1000 + ### Section: Construction and Destruction ### @@ -119,7 +121,7 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params - debouncedSaveStateSync = _.debounce((=> @saveStateSync()), 1000) + debouncedSaveStateSync = _.debounce((=> @saveStateSync()), @saveStateDebounceInterval) @document.addEventListener('mousedown', debouncedSaveStateSync, true) @document.addEventListener('keypress', debouncedSaveStateSync, true) From a2f9a8d32e5529b5f7ce4021104a4a836ae23b82 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 27 Jan 2016 23:52:41 -0700 Subject: [PATCH 08/66] Rename StorageFolder::store to ::storeSync --- src/atom-environment.coffee | 2 +- src/browser/atom-application.coffee | 2 +- src/storage-folder.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index cabd1896b..215bcd7ed 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -794,7 +794,7 @@ class AtomEnvironment extends Model @serialize() if storageKey = @getStateKey(@project?.getPaths()) - @getStorageFolder().store(storageKey, @state) + @getStorageFolder().storeSync(storageKey, @state) else @getCurrentWindow().loadSettings.windowState = JSON.stringify(@state) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 44848eb72..5ff24c458 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -472,7 +472,7 @@ class AtomApplication if loadSettings = window.getLoadSettings() states.push(initialPaths: loadSettings.initialPaths) if states.length > 0 or allowEmpty - @storageFolder.store('application.json', states) + @storageFolder.storeSync('application.json', states) loadState: (options) -> if (states = @storageFolder.load('application.json'))?.length > 0 diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index da8af3f2e..06beae56a 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -6,7 +6,7 @@ class StorageFolder constructor: (containingPath) -> @path = path.join(containingPath, "storage") if containingPath? - store: (name, object) -> + storeSync: (name, object) -> return unless @path? fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') From 5148b8ca3da6f36a050249751f5f6fb7f371e9f0 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 00:47:21 -0700 Subject: [PATCH 09/66] Save state on keydown rather than on keypress --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 215bcd7ed..fc89864eb 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -123,7 +123,7 @@ class AtomEnvironment extends Model debouncedSaveStateSync = _.debounce((=> @saveStateSync()), @saveStateDebounceInterval) @document.addEventListener('mousedown', debouncedSaveStateSync, true) - @document.addEventListener('keypress', debouncedSaveStateSync, true) + @document.addEventListener('keydown', debouncedSaveState, true) @state = {version: @constructor.version} From 54a03516bf51ddf00c6ea0c0dd057fd57e7e7222 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 00:56:52 -0700 Subject: [PATCH 10/66] Save state asynchronously on mousedown and keydown events. Tests WIP --- spec/atom-environment-spec.coffee | 19 ++++++++++--------- src/atom-environment.coffee | 14 ++++++++------ src/storage-folder.coffee | 5 +++++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 4621886dc..a575b993d 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -163,7 +163,7 @@ describe "AtomEnvironment", -> atom.state.stuff = "cool" atom.project.setPaths([dir1, dir2]) - atom.saveStateSync() + atom.saveState(true) atom.state = {} atom.loadStateSync() @@ -174,18 +174,18 @@ describe "AtomEnvironment", -> atom.loadStateSync() expect(atom.state.stuff).toBe("cool") - it "saves state on keypress and mousedown events", -> - spyOn(atom, 'saveStateSync') + it "saves state on keydown and mousedown events", -> + spyOn(atom, 'saveState') - keypress = new KeyboardEvent('keypress') - atom.document.dispatchEvent(keypress) + keydown = new KeyboardEvent('keydown') + atom.document.dispatchEvent(keydown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveStateSync).toHaveBeenCalled() + expect(atom.saveState).toHaveBeenCalled() mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveStateSync).toHaveBeenCalled() + expect(atom.saveState).toHaveBeenCalled() describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> @@ -243,9 +243,10 @@ describe "AtomEnvironment", -> atomEnvironment.destroy() + # TODO: fix failing test. devtools show that ::saveState just goes to jasmine.createSpy.spyObj function it "saves the serialized state of the window so it can be deserialized after reload", -> atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document}) - spyOn(atomEnvironment, 'saveStateSync') + spyOn(atomEnvironment, 'saveState') workspaceState = atomEnvironment.workspace.serialize() grammarsState = {grammarOverridesByPath: atomEnvironment.grammars.grammarOverridesByPath} @@ -256,7 +257,7 @@ describe "AtomEnvironment", -> expect(atomEnvironment.state.workspace).toEqual workspaceState expect(atomEnvironment.state.grammars).toEqual grammarsState expect(atomEnvironment.state.project).toEqual projectState - expect(atomEnvironment.saveStateSync).toHaveBeenCalled() + expect(atomEnvironment.saveState).toHaveBeenCalled() atomEnvironment.destroy() diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index fc89864eb..247b73b40 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -121,8 +121,8 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params - debouncedSaveStateSync = _.debounce((=> @saveStateSync()), @saveStateDebounceInterval) - @document.addEventListener('mousedown', debouncedSaveStateSync, true) + debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval) + @document.addEventListener('mousedown', debouncedSaveState, true) @document.addEventListener('keydown', debouncedSaveState, true) @state = {version: @constructor.version} @@ -653,9 +653,8 @@ class AtomEnvironment extends Model return if not @project @storeWindowBackground() - @serialize() + @saveState(true) @packages.deactivatePackages() - @saveStateSync() @saveBlobStoreSync() openInitialEmptyEditorIfNecessary: -> @@ -789,12 +788,15 @@ class AtomEnvironment extends Model @blobStore.save() - saveStateSync: -> + saveState: (synchronous) -> return unless @enablePersistence @serialize() if storageKey = @getStateKey(@project?.getPaths()) - @getStorageFolder().storeSync(storageKey, @state) + if synchronous + @getStorageFolder().storeSync(storageKey, @state) + else + @getStorageFolder().storeAsync(storageKey, @state) else @getCurrentWindow().loadSettings.windowState = JSON.stringify(@state) diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index 06beae56a..d94a6f013 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -11,6 +11,11 @@ class StorageFolder fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') + storeAsync: (name, object) -> + return unless @path? + + fs.writeFile(@pathForKey(name), JSON.stringify(object), 'utf8') + load: (name) -> return unless @path? From 29deb61d4ed084d44c32494c7e6b48c4d0a4d0cb Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 01:29:46 -0700 Subject: [PATCH 11/66] Remove AtomEnvironment state instance variable. Tests WIP --- src/atom-environment.coffee | 43 ++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 247b73b40..e4158accd 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -308,9 +308,6 @@ class AtomEnvironment extends Model @views.clear() @registerDefaultViewProviders() - @state.packageStates = {} - delete @state.workspace - destroy: -> return if not @project @@ -597,7 +594,7 @@ class AtomEnvironment extends Model {x: 0, y: 0, width: Math.min(1024, width), height} restoreWindowDimensions: -> - dimensions = @state.windowDimensions + dimensions = @windowDimensions unless @isValidDimensions(dimensions) dimensions = @getDefaultWindowDimensions() @setWindowDimensions(dimensions) @@ -605,7 +602,7 @@ class AtomEnvironment extends Model storeWindowDimensions: -> dimensions = @getWindowDimensions() - @state.windowDimensions = dimensions if @isValidDimensions(dimensions) + @windowDimensions = dimensions if @isValidDimensions(dimensions) storeWindowBackground: -> return if @inSpecMode() @@ -643,11 +640,11 @@ class AtomEnvironment extends Model @openInitialEmptyEditorIfNecessary() serialize: -> - @state.project = @project.serialize() - @state.workspace = @workspace.serialize() - @state.packageStates = @packages.serialize() - @state.grammars = {grammarOverridesByPath: @grammars.grammarOverridesByPath} - @state.fullScreen = @isFullScreen() + project: @project.serialize() + workspace: @workspace.serialize() + packageStates: @packages.serialize() + grammars: {grammarOverridesByPath: @grammars.grammarOverridesByPath} + fullScreen: @isFullScreen() unloadEditorWindow: -> return if not @project @@ -790,15 +787,15 @@ class AtomEnvironment extends Model saveState: (synchronous) -> return unless @enablePersistence - @serialize() + state = @serialize() if storageKey = @getStateKey(@project?.getPaths()) if synchronous - @getStorageFolder().storeSync(storageKey, @state) + @getStorageFolder().storeSync(storageKey, state) else - @getStorageFolder().storeAsync(storageKey, @state) + @getStorageFolder().storeAsync(storageKey, state) else - @getCurrentWindow().loadSettings.windowState = JSON.stringify(@state) + @getCurrentWindow().loadSettings.windowState = JSON.stringify(state) loadStateSync: -> return unless @enablePersistence @@ -806,31 +803,29 @@ class AtomEnvironment extends Model startTime = Date.now() if stateKey = @getStateKey(@getLoadSettings().initialPaths) - if state = @getStorageFolder().load(stateKey) - @state = state + state = @getStorageFolder().load(stateKey) - if not @state? and windowState = @getLoadSettings().windowState + if not state? and windowState = @getLoadSettings().windowState try - if state = JSON.parse(@getLoadSettings().windowState) - @state = state + state = JSON.parse(@getLoadSettings().windowState) catch error console.warn "Error parsing window state: #{statePath} #{error.stack}", error @deserializeTimings.atom = Date.now() - startTime - if grammarOverridesByPath = @state.grammars?.grammarOverridesByPath + if grammarOverridesByPath = state.grammars?.grammarOverridesByPath @grammars.grammarOverridesByPath = grammarOverridesByPath - @setFullScreen(@state.fullScreen) + @setFullScreen(state.fullScreen) - @packages.packageStates = @state.packageStates ? {} + @packages.packageStates = state.packageStates ? {} startTime = Date.now() - @project.deserialize(@state.project, @deserializers) if @state.project? + @project.deserialize(state.project, @deserializers) if state.project? @deserializeTimings.project = Date.now() - startTime startTime = Date.now() - @workspace.deserialize(@state.workspace, @deserializers) if @state.workspace? + @workspace.deserialize(state.workspace, @deserializers) if state.workspace? @deserializeTimings.workspace = Date.now() - startTime getStateKey: (paths) -> From dff4aa8e84f37590c3ae218708c66c285ffb93b7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 14:03:10 -0700 Subject: [PATCH 12/66] Use method name `store` rather than `storeAsync` --- src/atom-environment.coffee | 2 +- src/storage-folder.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index e4158accd..b6ebc172f 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -793,7 +793,7 @@ class AtomEnvironment extends Model if synchronous @getStorageFolder().storeSync(storageKey, state) else - @getStorageFolder().storeAsync(storageKey, state) + @getStorageFolder().store(storageKey, state) else @getCurrentWindow().loadSettings.windowState = JSON.stringify(state) diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index d94a6f013..ff3474198 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -11,7 +11,7 @@ class StorageFolder fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') - storeAsync: (name, object) -> + store: (name, object) -> return unless @path? fs.writeFile(@pathForKey(name), JSON.stringify(object), 'utf8') From a54f4679af66792322aa35edbfb21da41546b356 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 15:46:40 -0700 Subject: [PATCH 13/66] Fix tests --- spec/atom-environment-spec.coffee | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index a575b993d..856cd0338 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -160,19 +160,18 @@ describe "AtomEnvironment", -> spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings spyOn(atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-")) + spyOn(atom, 'serialize').andReturn({stuff: 'cool'}) + spyOn(atom, 'deserialize') - atom.state.stuff = "cool" atom.project.setPaths([dir1, dir2]) atom.saveState(true) - atom.state = {} atom.loadStateSync() - expect(atom.state.stuff).toBeUndefined() + expect(atom.deserialize).not.toHaveBeenCalled() loadSettings.initialPaths = [dir2, dir1] - atom.state = {} atom.loadStateSync() - expect(atom.state.stuff).toBe("cool") + expect(atom.deserialize).toHaveBeenCalledWith({stuff: 'cool'}) it "saves state on keydown and mousedown events", -> spyOn(atom, 'saveState') @@ -243,20 +242,11 @@ describe "AtomEnvironment", -> atomEnvironment.destroy() - # TODO: fix failing test. devtools show that ::saveState just goes to jasmine.createSpy.spyObj function it "saves the serialized state of the window so it can be deserialized after reload", -> atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document}) spyOn(atomEnvironment, 'saveState') - workspaceState = atomEnvironment.workspace.serialize() - grammarsState = {grammarOverridesByPath: atomEnvironment.grammars.grammarOverridesByPath} - projectState = atomEnvironment.project.serialize() - atomEnvironment.unloadEditorWindow() - - expect(atomEnvironment.state.workspace).toEqual workspaceState - expect(atomEnvironment.state.grammars).toEqual grammarsState - expect(atomEnvironment.state.project).toEqual projectState expect(atomEnvironment.saveState).toHaveBeenCalled() atomEnvironment.destroy() From 92bd5051b3f255d7035d70ea31674a14b4c70830 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 15:47:37 -0700 Subject: [PATCH 14/66] Add env version and window dimensions to serialized state --- src/atom-environment.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index b6ebc172f..8ed254223 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -640,11 +640,13 @@ class AtomEnvironment extends Model @openInitialEmptyEditorIfNecessary() serialize: -> + version: @constructor.version project: @project.serialize() workspace: @workspace.serialize() packageStates: @packages.serialize() grammars: {grammarOverridesByPath: @grammars.grammarOverridesByPath} fullScreen: @isFullScreen() + windowDimensions: @windowDimensions unloadEditorWindow: -> return if not @project From c9012a228843df07cf5cd32a32b3329f3fb75ab8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 15:48:45 -0700 Subject: [PATCH 15/66] Call AtomEnvironment::deserialize in AtomEnvironment::loadStateSync --- src/atom-environment.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 8ed254223..5c61b1439 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -813,6 +813,9 @@ class AtomEnvironment extends Model catch error console.warn "Error parsing window state: #{statePath} #{error.stack}", error + @deserialize(state) if state? + + deserialize: (state) -> @deserializeTimings.atom = Date.now() - startTime if grammarOverridesByPath = state.grammars?.grammarOverridesByPath From 9cec10d9c0c8851d10818f71605a25112f968fd5 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 22:48:31 -0700 Subject: [PATCH 16/66] Remove atom environment state instance variable --- src/atom-environment.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 5c61b1439..2ec28d230 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -125,7 +125,6 @@ class AtomEnvironment extends Model @document.addEventListener('mousedown', debouncedSaveState, true) @document.addEventListener('keydown', debouncedSaveState, true) - @state = {version: @constructor.version} @loadTime = null {devMode, safeMode, resourcePath} = @getLoadSettings() From 224b51d17c25633fe297b1dc84500e5c5d047960 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 28 Jan 2016 22:49:46 -0700 Subject: [PATCH 17/66] Add disposable for removing debouncedSaveState listener --- src/atom-environment.coffee | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 2ec28d230..4cb2e5928 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -4,7 +4,7 @@ ipc = require 'ipc' _ = require 'underscore-plus' {deprecate} = require 'grim' -{CompositeDisposable, Emitter} = require 'event-kit' +{CompositeDisposable, Disposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {mapSourcePosition} = require 'source-map-support' Model = require './model' @@ -121,11 +121,6 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params - debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval) - @document.addEventListener('mousedown', debouncedSaveState, true) - @document.addEventListener('keydown', debouncedSaveState, true) - - @loadTime = null {devMode, safeMode, resourcePath} = @getLoadSettings() @@ -205,6 +200,7 @@ class AtomEnvironment extends Model @registerDefaultViewProviders() @installUncaughtErrorHandler() + @attachSaveStateListeners() @installWindowEventHandler() @observeAutoHideMenuBar() @@ -218,6 +214,14 @@ class AtomEnvironment extends Model checkPortableHomeWritable() + attachSaveStateListeners: -> + debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval) + @document.addEventListener('mousedown', debouncedSaveState, true) + @document.addEventListener('keydown', debouncedSaveState, true) + @disposables.add new Disposable => + @document.removeEventListener('mousedown', debouncedSaveState, true) + @document.removeEventListener('keydown', debouncedSaveState, true) + setConfigSchema: -> @config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))} From 5e21f7bad9efcc519d291a2b5910a5f4fd5e8ce7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 1 Feb 2016 16:11:10 -0800 Subject: [PATCH 18/66] Serialize package upon deactivation --- spec/package-manager-spec.coffee | 7 ++++--- src/package-manager.coffee | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 8710927df..aa0b2d26f 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -445,11 +445,12 @@ describe "PackageManager", -> expect(console.warn).not.toHaveBeenCalled() it "passes the activate method the package's previously serialized state if it exists", -> - pack = atom.packages.loadPackage("package-with-serialization") + pack = null waitsForPromise -> - pack.activate() # require main module + atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p runs -> - atom.packages.setPackageState("package-with-serialization", {someNumber: 77}) + expect(pack.mainModule.someNumber).not.toBe 77 + pack.mainModule.someNumber = 77 atom.packages.deactivatePackage("package-with-serialization") spyOn(pack.mainModule, 'activate').andCallThrough() waitsForPromise -> diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 3a3a74711..636286640 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -487,6 +487,7 @@ class PackageManager # Deactivate the package with the given name deactivatePackage: (name) -> pack = @getLoadedPackage(name) + @serializePackage(pack) pack.deactivate() delete @activePackages[pack.name] delete @activatingPackages[pack.name] From 81f30d49089cd7853763dc8d2a480d1ec7eca2ab Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 1 Feb 2016 16:49:21 -0800 Subject: [PATCH 19/66] Only call package serialize methods once on quit --- src/atom-environment.coffee | 2 +- src/package-manager.coffee | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 4cb2e5928..68711b260 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -655,8 +655,8 @@ class AtomEnvironment extends Model return if not @project @storeWindowBackground() - @saveState(true) @packages.deactivatePackages() + @saveState(true) @saveBlobStoreSync() openInitialEmptyEditorIfNecessary: -> diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 636286640..705755af0 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -468,13 +468,12 @@ class PackageManager @activationHookEmitter.on(hook, callback) serialize: -> - for pack in @getLoadedPackages() + for pack in @getActivePackages() @serializePackage(pack) @packageStates serializePackage: (pack) -> - if @isPackageActive(pack.name) - @setPackageState(pack.name, state) if state = pack.serialize?() + @setPackageState(pack.name, state) if state = pack.serialize?() # Deactivate all packages deactivatePackages: -> @@ -487,7 +486,7 @@ class PackageManager # Deactivate the package with the given name deactivatePackage: (name) -> pack = @getLoadedPackage(name) - @serializePackage(pack) + @serializePackage(pack) if @isPackageActive(pack.name) pack.deactivate() delete @activePackages[pack.name] delete @activatingPackages[pack.name] From 3b500daab4d552b61e882d0a99872135f5c47552 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 4 Feb 2016 21:43:44 -0800 Subject: [PATCH 20/66] Create StateStore class and specs for storing state in IndexedDB --- spec/state-store-spec.js | 37 +++++++++++++++++++++++++++++++++ src/state-store.js | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 spec/state-store-spec.js create mode 100644 src/state-store.js diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js new file mode 100644 index 000000000..f505cf607 --- /dev/null +++ b/spec/state-store-spec.js @@ -0,0 +1,37 @@ +/** @babel */ +import {it, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' + +const StateStore = require('../src/state-store.js') + +describe("StateStore", () => { + it("can save and load states", () => { + const store = new StateStore() + return store.save('key', {foo:'bar'}) + .then(() => store.load('key')) + .then((state) => { + expect(state).toEqual({foo:'bar'}) + }) + }) + + describe("when there is an error reading from the database", () => { + it("rejects the promise returned by load", () => { + const store = new StateStore() + + const fakeErrorEvent = {target: {errorCode: "Something bad happened"}} + + spyOn(IDBObjectStore.prototype, 'get').andCallFake((key) => { + let request = {} + process.nextTick(() => request.onerror(fakeErrorEvent)) + return request + }) + + return store.load('nonexistentKey') + .then(() => { + throw new Error("Promise should have been rejected") + }) + .catch((event) => { + expect(event).toBe(fakeErrorEvent) + }) + }) + }) +}) diff --git a/src/state-store.js b/src/state-store.js new file mode 100644 index 000000000..7d6ee79f6 --- /dev/null +++ b/src/state-store.js @@ -0,0 +1,45 @@ +'use strict' + +module.exports = +class StateStore { + constructor () { + this.dbPromise = new Promise((resolve, reject) => { + let dbOpenRequest = indexedDB.open('AtomEnvironments', 1) + dbOpenRequest.onupgradeneeded = (event) => { + let db = event.target.result + db.createObjectStore('states') + resolve(db) + } + dbOpenRequest.onsuccess = () => { + resolve(dbOpenRequest.result) + } + dbOpenRequest.onerror = reject + }) + } + + save (key, value) { + return this.dbPromise.then(db => { + return new Promise((resolve, reject) => { + var request = db.transaction(['states'], 'readwrite') + .objectStore('states') + .put(value, key) + + request.onsuccess = resolve + request.onerror = reject + }) + }) + } + + load (key) { + return this.dbPromise.then(db => { + return new Promise((resolve, reject) => { + var request = db.transaction(['states']) + .objectStore('states') + .get(key) + + request.onsuccess = (event) => resolve(event.target.result) + request.onerror = (event) => reject(event) + }) + }) + } +} From 6e0328b048af8e9d297a81e07784e3bd5762fbdf Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 4 Feb 2016 21:45:00 -0800 Subject: [PATCH 21/66] Refactor to use StateStore instead of StorageFolder --- spec/atom-environment-spec.coffee | 34 +++++++-------- src/atom-environment.coffee | 54 ++++++++++++------------ src/initialize-application-window.coffee | 12 +++--- 3 files changed, 48 insertions(+), 52 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 856cd0338..5afb5169b 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -159,19 +159,22 @@ describe "AtomEnvironment", -> windowState: null spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings - spyOn(atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-")) spyOn(atom, 'serialize').andReturn({stuff: 'cool'}) spyOn(atom, 'deserialize') atom.project.setPaths([dir1, dir2]) - atom.saveState(true) + waitsForPromise -> + atom.saveState().then -> + atom.loadState() - atom.loadStateSync() - expect(atom.deserialize).not.toHaveBeenCalled() + runs -> + expect(atom.deserialize).not.toHaveBeenCalled() - loadSettings.initialPaths = [dir2, dir1] - atom.loadStateSync() - expect(atom.deserialize).toHaveBeenCalledWith({stuff: 'cool'}) + waitsForPromise -> + loadSettings.initialPaths = [dir2, dir1] + atom.loadState() + runs -> + expect(atom.deserialize).toHaveBeenCalledWith({stuff: 'cool'}) it "saves state on keydown and mousedown events", -> spyOn(atom, 'saveState') @@ -242,15 +245,6 @@ describe "AtomEnvironment", -> atomEnvironment.destroy() - it "saves the serialized state of the window so it can be deserialized after reload", -> - atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document}) - spyOn(atomEnvironment, 'saveState') - - atomEnvironment.unloadEditorWindow() - expect(atomEnvironment.saveState).toHaveBeenCalled() - - atomEnvironment.destroy() - describe "::destroy()", -> it "does not throw exceptions when unsubscribing from ipc events (regression)", -> configDirPath = temp.mkdirSync() @@ -262,9 +256,11 @@ describe "AtomEnvironment", -> } atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document: fakeDocument}) spyOn(atomEnvironment.packages, 'getAvailablePackagePaths').andReturn [] - atomEnvironment.startEditorWindow() - atomEnvironment.unloadEditorWindow() - atomEnvironment.destroy() + waitsForPromise -> + atomEnvironment.startEditorWindow() + runs -> + atomEnvironment.unloadEditorWindow() + atomEnvironment.destroy() describe "::openLocations(locations) (called via IPC from browser process)", -> beforeEach -> diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 68711b260..84f1cb23e 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -10,7 +10,7 @@ fs = require 'fs-plus' Model = require './model' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' -StorageFolder = require './storage-folder' +StateStore = require './state-store' {getWindowLoadSettings} = require './window-load-settings-helpers' registerDefaultCommands = require './register-default-commands' @@ -127,6 +127,8 @@ class AtomEnvironment extends Model @emitter = new Emitter @disposables = new CompositeDisposable + @stateStore = new StateStore + @deserializers = new DeserializerManager(this) @deserializeTimings = {} @@ -629,18 +631,18 @@ class AtomEnvironment extends Model @registerDefaultTargetForKeymaps() @packages.loadPackages() - @loadStateSync() - @document.body.appendChild(@views.getView(@workspace)) + @loadState().then => + @document.body.appendChild(@views.getView(@workspace)) - @watchProjectPath() + @watchProjectPath() - @packages.activate() - @keymaps.loadUserKeymap() - @requireUserInitScript() unless @getLoadSettings().safeMode + @packages.activate() + @keymaps.loadUserKeymap() + @requireUserInitScript() unless @getLoadSettings().safeMode - @menu.update() + @menu.update() - @openInitialEmptyEditorIfNecessary() + @openInitialEmptyEditorIfNecessary() serialize: -> version: @constructor.version @@ -656,7 +658,6 @@ class AtomEnvironment extends Model @storeWindowBackground() @packages.deactivatePackages() - @saveState(true) @saveBlobStoreSync() openInitialEmptyEditorIfNecessary: -> @@ -790,37 +791,39 @@ class AtomEnvironment extends Model @blobStore.save() - saveState: (synchronous) -> - return unless @enablePersistence + saveState: () -> + return Promise.resolve() unless @enablePersistence state = @serialize() if storageKey = @getStateKey(@project?.getPaths()) - if synchronous - @getStorageFolder().storeSync(storageKey, state) - else - @getStorageFolder().store(storageKey, state) + @stateStore.save(storageKey, state) else @getCurrentWindow().loadSettings.windowState = JSON.stringify(state) + Promise.resolve() - loadStateSync: -> - return unless @enablePersistence + loadState: -> + return Promise.resolve() unless @enablePersistence startTime = Date.now() + statePromise = null if stateKey = @getStateKey(@getLoadSettings().initialPaths) - state = @getStorageFolder().load(stateKey) + statePromise = @stateStore.load(stateKey) - if not state? and windowState = @getLoadSettings().windowState + if not statePromise? and windowState = @getLoadSettings().windowState try - state = JSON.parse(@getLoadSettings().windowState) + statePromise = Promise.resolve(JSON.parse(@getLoadSettings().windowState)) catch error console.warn "Error parsing window state: #{statePath} #{error.stack}", error - @deserialize(state) if state? + if statePromise? + statePromise.then (state) => + @deserializeTimings.atom = Date.now() - startTime + @deserialize(state) if state? + else + Promise.resolve() deserialize: (state) -> - @deserializeTimings.atom = Date.now() - startTime - if grammarOverridesByPath = state.grammars?.grammarOverridesByPath @grammars.grammarOverridesByPath = grammarOverridesByPath @@ -846,9 +849,6 @@ class AtomEnvironment extends Model getConfigDirPath: -> @configDirPath ?= process.env.ATOM_HOME - getStorageFolder: -> - @storageFolder ?= new StorageFolder(@getConfigDirPath()) - getUserInitScriptPath: -> initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee']) initScriptPath ? path.join(@getConfigDirPath(), 'init.coffee') diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 57aa33ce0..45e18163d 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -24,10 +24,10 @@ module.exports = ({blobStore}) -> }) atom.displayWindow() - atom.startEditorWindow() + atom.startEditorWindow().then -> - # Workaround for focus getting cleared upon window creation - windowFocused = -> - window.removeEventListener('focus', windowFocused) - setTimeout (-> document.querySelector('atom-workspace').focus()), 0 - window.addEventListener('focus', windowFocused) + # Workaround for focus getting cleared upon window creation + windowFocused = -> + window.removeEventListener('focus', windowFocused) + setTimeout (-> document.querySelector('atom-workspace').focus()), 0 + window.addEventListener('focus', windowFocused) From 85b32b861ed2f6463ef640a4c4bd1ffb9e55783c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 5 Feb 2016 16:49:23 -0800 Subject: [PATCH 22/66] Add storedAt date for serialized environment state --- src/state-store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/state-store.js b/src/state-store.js index 7d6ee79f6..f07560038 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -19,6 +19,7 @@ class StateStore { save (key, value) { return this.dbPromise.then(db => { + value.storedAt = new Date().toString() return new Promise((resolve, reject) => { var request = db.transaction(['states'], 'readwrite') .objectStore('states') From f3b39ad82e85a398b33d8a64d504ca7b289e728f Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 8 Feb 2016 14:44:12 -0800 Subject: [PATCH 23/66] =?UTF-8?q?Add=20=E2=80=98indexedDB=E2=80=99=20to=20?= =?UTF-8?q?list=20of=20known=20global=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 322b3c784..94ab84a68 100644 --- a/package.json +++ b/package.json @@ -173,7 +173,8 @@ "runs", "spyOn", "waitsFor", - "waitsForPromise" + "waitsForPromise", + "indexedDB" ] } } From f3a6a1d52283b72fe9fcc23b6c7f5b88545c6096 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 8 Feb 2016 14:44:35 -0800 Subject: [PATCH 24/66] Use prerelease version of text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94ab84a68..fced6c777 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.1.4", + "text-buffer": "8.2.2-1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From dc355629624a7f7852a6b68079862d28eb325df7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 8 Feb 2016 15:12:46 -0800 Subject: [PATCH 25/66] Remove empty parameter list in order to pass linter --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 84f1cb23e..a2b56fdd4 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -791,7 +791,7 @@ class AtomEnvironment extends Model @blobStore.save() - saveState: () -> + saveState: -> return Promise.resolve() unless @enablePersistence state = @serialize() From 9b2c791c86443387c16b3d858dbdd22f070bd9cd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Feb 2016 14:28:01 -0800 Subject: [PATCH 26/66] Don't emit window:loaded event until async window initialization completes Signed-off-by: Katrina Uychaco --- src/initialize-test-window.coffee | 4 +++- static/index.js | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/initialize-test-window.coffee b/src/initialize-test-window.coffee index f3507b479..bdd94461a 100644 --- a/src/initialize-test-window.coffee +++ b/src/initialize-test-window.coffee @@ -68,7 +68,9 @@ module.exports = ({blobStore}) -> logFile, headless, testPaths, buildAtomEnvironment, buildDefaultApplicationDelegate, legacyTestRunner }) - promise.then(exitWithStatusCode) if getWindowLoadSettings().headless + promise.then (statusCode) -> + exitWithStatusCode(statusCode) if getWindowLoadSettings().headless + catch error if getWindowLoadSettings().headless console.error(error.stack ? error) diff --git a/static/index.js b/static/index.js index 6d65d3c52..651c2afe6 100644 --- a/static/index.js +++ b/static/index.js @@ -83,8 +83,9 @@ setupCsonCache(CompileCache.getCacheDirectory()) var initialize = require(loadSettings.windowInitializationScript) - initialize({blobStore: blobStore}) - require('ipc').sendChannel('window-command', 'window:loaded') + initialize({blobStore: blobStore}).then(function () { + require('ipc').sendChannel('window-command', 'window:loaded') + }) } function setupCsonCache (cacheDir) { From b0cf440f9cc294fa49a4d4c815615e1db6314288 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Feb 2016 14:30:10 -0800 Subject: [PATCH 27/66] Handle database connection errors gracefully When opening a second Atom instance (e.g. when running the integration specs) indexedDB connections will fail. In this case, StateStore.prototype.save and StateStore.prototype.load will become noops. Signed-off-by: Katrina Uychaco --- spec/state-store-spec.js | 16 +++++++++++++--- src/atom-environment.coffee | 2 +- src/state-store.js | 29 +++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index f505cf607..955ceb767 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,11 +1,14 @@ /** @babel */ -import {it, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' const StateStore = require('../src/state-store.js') describe("StateStore", () => { + let databaseName = `test-database-${Date.now()}` + let version = 1 + it("can save and load states", () => { - const store = new StateStore() + const store = new StateStore(databaseName, version) return store.save('key', {foo:'bar'}) .then(() => store.load('key')) .then((state) => { @@ -13,9 +16,16 @@ describe("StateStore", () => { }) }) + it("resolves with null when a non-existent key is loaded", () => { + const store = new StateStore(databaseName, version) + return store.load('no-such-key').then((value) => { + expect(value).toBeNull() + }) + }); + describe("when there is an error reading from the database", () => { it("rejects the promise returned by load", () => { - const store = new StateStore() + const store = new StateStore(databaseName, version) const fakeErrorEvent = {target: {errorCode: "Something bad happened"}} diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 141c1c112..c02ac59c7 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -127,7 +127,7 @@ class AtomEnvironment extends Model @emitter = new Emitter @disposables = new CompositeDisposable - @stateStore = new StateStore + @stateStore = new StateStore('AtomEnvironments', 1) @deserializers = new DeserializerManager(this) @deserializeTimings = {} diff --git a/src/state-store.js b/src/state-store.js index f07560038..817d4282f 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -2,28 +2,33 @@ module.exports = class StateStore { - constructor () { - this.dbPromise = new Promise((resolve, reject) => { - let dbOpenRequest = indexedDB.open('AtomEnvironments', 1) + constructor (databaseName, version) { + this.dbPromise = new Promise((resolve) => { + let dbOpenRequest = indexedDB.open(databaseName, version) dbOpenRequest.onupgradeneeded = (event) => { let db = event.target.result db.createObjectStore('states') - resolve(db) } dbOpenRequest.onsuccess = () => { resolve(dbOpenRequest.result) } - dbOpenRequest.onerror = reject + dbOpenRequest.onerror = (error) => { + console.error("Could not connect to indexedDB", error) + resolve(null) + } }) } save (key, value) { return this.dbPromise.then(db => { - value.storedAt = new Date().toString() + if (!db) { + return + } + return new Promise((resolve, reject) => { var request = db.transaction(['states'], 'readwrite') .objectStore('states') - .put(value, key) + .put({value: value, storedAt: new Date().toString()}, key) request.onsuccess = resolve request.onerror = reject @@ -33,12 +38,20 @@ class StateStore { load (key) { return this.dbPromise.then(db => { + if (!db) { + return null + } + return new Promise((resolve, reject) => { var request = db.transaction(['states']) .objectStore('states') .get(key) - request.onsuccess = (event) => resolve(event.target.result) + request.onsuccess = (event) => { + let result = event.target.result + resolve(result ? result.value : null) + } + request.onerror = (event) => reject(event) }) }) From 0f02663f6be31dae4f8f1871268e7bae53aad064 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Feb 2016 14:30:58 -0800 Subject: [PATCH 28/66] Add --user-data-dir flag, to control indexedDB directory This way, we can still use indexedDB in the integration tests Signed-off-by: Katrina Uychaco --- spec/integration/helpers/start-atom.coffee | 4 +++- spec/integration/startup-spec.coffee | 2 ++ src/browser/main.coffee | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 3c1016ad2..af9ce094b 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -15,6 +15,8 @@ ChromedriverPort = 9515 ChromedriverURLBase = "/wd/hub" ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status" +userDataDir = temp.mkdirSync('atom-user-data-dir') + chromeDriverUp = (done) -> checkStatus = -> http @@ -48,7 +50,7 @@ buildAtomClient = (args, env) -> "atom-env=#{map(env, (value, key) -> "#{key}=#{value}").join(" ")}" "dev" "safe" - "user-data-dir=#{temp.mkdirSync('atom-user-data-dir')}" + "user-data-dir=#{userDataDir}" "socket-path=#{SocketPath}" ]) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 6e8a7f55a..f22e7ae2c 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -153,6 +153,8 @@ describe "Starting Atom", -> .waitForPaneItemCount(0, 3000) .execute -> atom.workspace.open() .waitForPaneItemCount(1, 3000) + .keys("Hello!") + .waitUntil((-> Promise.resolve(false)), 1100) runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> client diff --git a/src/browser/main.coffee b/src/browser/main.coffee index ca9d7e3ae..bbce1d87f 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -32,6 +32,9 @@ start = -> app.on 'open-url', addUrlToOpen app.on 'will-finish-launching', setupCrashReporter + if args.userDataDir? + app.setPath('userData', args.userDataDir) + app.on 'ready', -> app.removeListener 'open-file', addPathToOpen app.removeListener 'open-url', addUrlToOpen @@ -119,6 +122,7 @@ parseCommandLine = -> options.alias('v', 'version').boolean('v').describe('v', 'Print the version.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') + options.string('user-data-dir') args = options.argv @@ -140,6 +144,7 @@ parseCommandLine = -> pidToKillWhenClosed = args['pid'] if args['wait'] logFile = args['log-file'] socketPath = args['socket-path'] + userDataDir = args['user-data-dir'] profileStartup = args['profile-startup'] urlsToOpen = [] devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getHomeDir(), 'github', 'atom') @@ -164,6 +169,6 @@ parseCommandLine = -> {resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, - logFile, socketPath, profileStartup, timeout, setPortable} + logFile, socketPath, userDataDir, profileStartup, timeout, setPortable} start() From fa70560eba330e2b8f31add9d93d8f4a2173607a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 9 Feb 2016 14:34:32 -0800 Subject: [PATCH 29/66] :shirt: Use single quotes in JS string Signed-off-by: Katrina Uychaco --- src/state-store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state-store.js b/src/state-store.js index 817d4282f..f5e687d4f 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -13,7 +13,7 @@ class StateStore { resolve(dbOpenRequest.result) } dbOpenRequest.onerror = (error) => { - console.error("Could not connect to indexedDB", error) + console.error('Could not connect to indexedDB', error) resolve(null) } }) From 7b808257a60103d1e1f78fec9d8a028731ecbdd9 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 10 Feb 2016 11:04:30 -0800 Subject: [PATCH 30/66] Add test to check for indexedDB connection --- spec/atom-environment-spec.coffee | 7 +++++++ src/state-store.js | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 5afb5169b..7aaed602b 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -152,6 +152,8 @@ describe "AtomEnvironment", -> atom.enablePersistence = false it "selects the state based on the current project paths", -> + jasmine.useRealClock() + [dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")] loadSettings = _.extend atom.getLoadSettings(), @@ -163,6 +165,11 @@ describe "AtomEnvironment", -> spyOn(atom, 'deserialize') atom.project.setPaths([dir1, dir2]) + # State persistence will fail if other Atom instances are running + waitsForPromise -> + atom.stateStore.connect().then (isConnected) -> + expect(isConnected).toBe true + waitsForPromise -> atom.saveState().then -> atom.loadState() diff --git a/src/state-store.js b/src/state-store.js index f5e687d4f..feefbbb34 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -19,6 +19,10 @@ class StateStore { }) } + connect () { + return this.dbPromise.then(db => !!db) + } + save (key, value) { return this.dbPromise.then(db => { if (!db) { From 285c082ac0ecaeb2464040f8d1c9b25fc77e7e87 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Wed, 10 Feb 2016 12:37:31 -0800 Subject: [PATCH 31/66] Use text-buffer 8.2.2-2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f883ee866..68f7c3bae 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.2.2-1", + "text-buffer": "8.2.2-2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From f6ced98be873739dd4233ab16192019324dc5c4e Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 11:43:41 -0800 Subject: [PATCH 32/66] Fix bug from merge with PR#10743 --- src/atom-environment.coffee | 20 +++++++++++--------- src/initialize-application-window.coffee | 6 +++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 2d7427ba0..f7869f9af 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -615,7 +615,7 @@ class AtomEnvironment extends Model # But after that, e.g., when the window's been reloaded, we want to use the # dimensions we've saved for it. if not @isFirstLoad() - dimensions = @state.windowDimensions + dimensions = @windowDimensions unless @isValidDimensions(dimensions) dimensions = @getDefaultWindowDimensions() @@ -648,18 +648,18 @@ class AtomEnvironment extends Model @registerDefaultTargetForKeymaps() @packages.loadPackages() - @loadState().then => - @document.body.appendChild(@views.getView(@workspace)) + + @document.body.appendChild(@views.getView(@workspace)) - @watchProjectPath() + @watchProjectPath() - @packages.activate() - @keymaps.loadUserKeymap() - @requireUserInitScript() unless @getLoadSettings().safeMode + @packages.activate() + @keymaps.loadUserKeymap() + @requireUserInitScript() unless @getLoadSettings().safeMode - @menu.update() + @menu.update() - @openInitialEmptyEditorIfNecessary() + @openInitialEmptyEditorIfNecessary() serialize: -> version: @constructor.version @@ -846,6 +846,8 @@ class AtomEnvironment extends Model @setFullScreen(state.fullScreen) + @windowDimensions = state.windowDimensions if state.windowDimensions + @packages.packageStates = state.packageStates ? {} startTime = Date.now() diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 0044a8d18..e4fa4af4d 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -23,9 +23,9 @@ module.exports = ({blobStore}) -> enablePersistence: true }) - atom.loadStateSync() - atom.displayWindow() - atom.startEditorWindow().then -> + atom.loadState().then -> + atom.displayWindow() + atom.startEditorWindow() # Workaround for focus getting cleared upon window creation windowFocused = -> From 8e33f8bf5b974a690cf291dcfad5a38b5cc12a57 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 11:50:44 -0800 Subject: [PATCH 33/66] Wait for tab to open in webdriverio `waitForPaneItemCount` command --- spec/integration/helpers/start-atom.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index af9ce094b..9df884286 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -85,7 +85,8 @@ buildAtomClient = (args, env) -> .addCommand "waitForPaneItemCount", (count, timeout, cb) -> @waitUntil(-> - @execute(-> atom.workspace?.getActivePane()?.getItems().length) + @waitForExist('.tab', 10000) + .execute(-> atom.workspace?.getActivePane()?.getItems().length) .then(({value}) -> value is count) , timeout) .then (result) -> From c2ff75f94bf1a0382ea46c01e8c39c7a1676cce9 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 13:57:20 -0800 Subject: [PATCH 34/66] Use `user-data-dir` with temp directory when running core tests This is to ensure successful database connection. Since core specs and package specs are run at the same time and both open an indexedDB connection, there were occasional core spec failures due to failed database connection. --- build/tasks/spec-task.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 892c92696..1d4be1e6f 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -1,5 +1,6 @@ fs = require 'fs' path = require 'path' +temp = require('temp').track() _ = require 'underscore-plus' async = require 'async' @@ -94,7 +95,7 @@ module.exports = (grunt) -> if process.platform in ['darwin', 'linux'] options = cmd: appPath - args: ['--test', "--resource-path=#{resourcePath}", coreSpecsPath] + args: ['--test', "--resource-path=#{resourcePath}", coreSpecsPath, "--user-data-dir=#{temp.mkdirSync('atom-user-data-dir')}"] opts: env: _.extend({}, process.env, ATOM_INTEGRATION_TESTS_ENABLED: true From 5e7f2741b43cbaacb2e5a2be1ab7505bd4d63ab7 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 14:50:30 -0800 Subject: [PATCH 35/66] In startup-spec check pane item count after editor has been loaded --- spec/integration/startup-spec.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index f22e7ae2c..e82d34e57 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -28,13 +28,12 @@ describe "Starting Atom", -> it "opens the parent directory and creates an empty text editor", -> runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) -> client - .waitForPaneItemCount(1, 1000) - .treeViewRootDirectories() .then ({value}) -> expect(value).toEqual([tempDirPath]) .waitForExist("atom-text-editor", 5000) .then (exists) -> expect(exists).toBe true + .waitForPaneItemCount(1, 1000) .click("atom-text-editor") .keys("Hello!") .execute -> atom.workspace.getActiveTextEditor().getText() From 7cfe0b659e0e7bba6e452e99d6d5652050e37d8c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 14:50:51 -0800 Subject: [PATCH 36/66] Revert "Wait for tab to open in webdriverio `waitForPaneItemCount` command" This reverts commit 8e33f8bf5b974a690cf291dcfad5a38b5cc12a57. --- spec/integration/helpers/start-atom.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/integration/helpers/start-atom.coffee b/spec/integration/helpers/start-atom.coffee index 9df884286..af9ce094b 100644 --- a/spec/integration/helpers/start-atom.coffee +++ b/spec/integration/helpers/start-atom.coffee @@ -85,8 +85,7 @@ buildAtomClient = (args, env) -> .addCommand "waitForPaneItemCount", (count, timeout, cb) -> @waitUntil(-> - @waitForExist('.tab', 10000) - .execute(-> atom.workspace?.getActivePane()?.getItems().length) + @execute(-> atom.workspace?.getActivePane()?.getItems().length) .then(({value}) -> value is count) , timeout) .then (result) -> From 6f4936983e60afd1cb70b68c28a11ad08ac2364d Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 15:40:04 -0800 Subject: [PATCH 37/66] Revert test since `startEditorWindow` no longer returns a promise --- spec/atom-environment-spec.coffee | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 7aaed602b..561ecf3b5 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -263,11 +263,9 @@ describe "AtomEnvironment", -> } atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document: fakeDocument}) spyOn(atomEnvironment.packages, 'getAvailablePackagePaths').andReturn [] - waitsForPromise -> - atomEnvironment.startEditorWindow() - runs -> - atomEnvironment.unloadEditorWindow() - atomEnvironment.destroy() + atomEnvironment.startEditorWindow() + atomEnvironment.unloadEditorWindow() + atomEnvironment.destroy() describe "::openLocations(locations) (called via IPC from browser process)", -> beforeEach -> From 255b943d45344c13596e8b3420c142d29e1d14ba Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 19:56:25 -0800 Subject: [PATCH 38/66] Add ability to clear IndexedDB state object store --- spec/state-store-spec.js | 16 +++++++++++++++- src/state-store.js | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 955ceb767..95fdcb71b 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -21,7 +21,21 @@ describe("StateStore", () => { return store.load('no-such-key').then((value) => { expect(value).toBeNull() }) - }); + }) + + it("can clear the state object store", () => { + const store = new StateStore(databaseName, version) + return store.save('key', {foo:'bar'}) + .then(() => store.count()) + .then((count) => + expect(count).toBe(1) + ) + .then(() => store.clear()) + .then(() => store.count()) + .then((count) => { + expect(count).toBe(0) + }) + }) describe("when there is an error reading from the database", () => { it("rejects the promise returned by load", () => { diff --git a/src/state-store.js b/src/state-store.js index feefbbb34..2175bbe4c 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -25,9 +25,7 @@ class StateStore { save (key, value) { return this.dbPromise.then(db => { - if (!db) { - return - } + if (!db) return return new Promise((resolve, reject) => { var request = db.transaction(['states'], 'readwrite') @@ -42,9 +40,7 @@ class StateStore { load (key) { return this.dbPromise.then(db => { - if (!db) { - return null - } + if (!db) return return new Promise((resolve, reject) => { var request = db.transaction(['states']) @@ -60,4 +56,36 @@ class StateStore { }) }) } + + clear () { + return this.dbPromise.then(db => { + if (!db) return + + return new Promise((resolve, reject) => { + var request = db.transaction(['states'], 'readwrite') + .objectStore('states') + .clear() + + request.onsuccess = resolve + request.onerror = reject + }) + }) + } + + count () { + return this.dbPromise.then(db => { + if (!db) return + + return new Promise((resolve, reject) => { + var request = db.transaction(['states']) + .objectStore('states') + .count() + + request.onsuccess = () => { + resolve(request.result) + } + request.onerror = reject + }) + }) + } } From 3e7de735804ae7709ecef671b922e7fa00db5a59 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 09:58:37 -0500 Subject: [PATCH 39/66] Bump the timeout. --- spec/text-editor-presenter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 9253ff103..90ef56da0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -91,7 +91,7 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) waitsForStateToUpdate = (presenter, fn) -> - waitsFor "presenter state to update", 1000, (done) -> + waitsFor "presenter state to update", 2000, (done) -> fn?() disposable = presenter.onDidUpdateState -> disposable.dispose() From dd6a6be8b19315b65f5d39cd75957fefc98e33f8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 10:56:36 -0500 Subject: [PATCH 40/66] Once more, with feeling. --- spec/text-editor-presenter-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 90ef56da0..d16e8dff4 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -91,7 +91,7 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) waitsForStateToUpdate = (presenter, fn) -> - waitsFor "presenter state to update", 2000, (done) -> + waitsFor "presenter state to update", 5000, (done) -> fn?() disposable = presenter.onDidUpdateState -> disposable.dispose() From a3ec51f492272fdf69e9660bec552e97773e811d Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 11:46:43 -0500 Subject: [PATCH 41/66] Let's try rearranging this. --- spec/text-editor-presenter-spec.coffee | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d16e8dff4..0c60ce30b 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -90,6 +90,15 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) + waitsForStateToUpdate2 = (presenter, fn) -> + didUpdate = false + disposable = presenter.onDidUpdateState -> + disposable.dispose() + didUpdate = true + fn?() + waitsFor "presenter state to update", 5000, (done) -> + didUpdate + waitsForStateToUpdate = (presenter, fn) -> waitsFor "presenter state to update", 5000, (done) -> fn?() @@ -1680,7 +1689,7 @@ describe "TextEditorPresenter", -> blockDecoration1 = addBlockDecorationBeforeScreenRow(0) blockDecoration2 = addBlockDecorationBeforeScreenRow(1) - waitsForStateToUpdate presenter, -> + waitsForStateToUpdate2 presenter, -> presenter.setBlockDecorationDimensions(blockDecoration1, 0, 30) presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10) @@ -1691,7 +1700,7 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 3)).toBeUndefined() expect(stateForCursor(presenter, 4)).toBeUndefined() - waitsForStateToUpdate presenter, -> + waitsForStateToUpdate2 presenter, -> blockDecoration2.destroy() editor.setCursorBufferPosition([0, 0]) editor.insertNewline() From 07d35245e0cc716253ba520ffeaab6c2ebf30f19 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 11:51:48 -0500 Subject: [PATCH 42/66] Move it around again. --- spec/text-editor-presenter-spec.coffee | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 0c60ce30b..d8f98afd2 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -91,13 +91,11 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) waitsForStateToUpdate2 = (presenter, fn) -> - didUpdate = false - disposable = presenter.onDidUpdateState -> - disposable.dispose() - didUpdate = true - fn?() waitsFor "presenter state to update", 5000, (done) -> - didUpdate + disposable = presenter.onDidUpdateState -> + disposable.dispose() + process.nextTick(done) + fn?() waitsForStateToUpdate = (presenter, fn) -> waitsFor "presenter state to update", 5000, (done) -> From 319043c93d230eb625ef5cb1041eb03a7e77ba06 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 12:11:52 -0500 Subject: [PATCH 43/66] Update this test too. --- spec/text-editor-presenter-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d8f98afd2..8251a9593 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -3467,9 +3467,9 @@ describe "TextEditorPresenter", -> gutterName: 'test-gutter-2' class: 'test-class' marker4 = editor.markBufferRange([[0, 0], [1, 0]]) - decoration4 = editor.decorateMarker(marker4, decorationParams) + decoration4 = null - waitsForStateToUpdate presenter + waitsForStateToUpdate2 presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams) runs -> expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) From 8b14f5afdcedc20d7688e910d782db411f5a703c Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 13:58:38 -0500 Subject: [PATCH 44/66] Let's get some deterministic failures. --- spec/text-editor-presenter-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 8251a9593..b3fd46048 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -20,6 +20,7 @@ describe "TextEditorPresenter", -> buffer = new TextBuffer(filePath: require.resolve('./fixtures/sample.js')) editor = atom.workspace.buildTextEditor({buffer}) + editor.setUpdatedSynchronously(true) waitsForPromise -> buffer.load() afterEach -> From 272ff19d7ba6acf35e7abb68abaf846601f90bd6 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 13:58:54 -0500 Subject: [PATCH 45/66] Decrease the timeout interval. --- spec/text-editor-presenter-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index b3fd46048..3d775bda9 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -92,14 +92,14 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) waitsForStateToUpdate2 = (presenter, fn) -> - waitsFor "presenter state to update", 5000, (done) -> + waitsFor "presenter state to update", 1000, (done) -> disposable = presenter.onDidUpdateState -> disposable.dispose() process.nextTick(done) fn?() waitsForStateToUpdate = (presenter, fn) -> - waitsFor "presenter state to update", 5000, (done) -> + waitsFor "presenter state to update", 1000, (done) -> fn?() disposable = presenter.onDidUpdateState -> disposable.dispose() From 6813bf50a058509fdc089da527d402cf3f2fc44e Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 14:00:47 -0500 Subject: [PATCH 46/66] Use waitsForStateToUpdateAsync in a bunch of places. --- spec/text-editor-presenter-spec.coffee | 63 +++++++++++++------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 3d775bda9..c3abeb062 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -91,7 +91,7 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) - waitsForStateToUpdate2 = (presenter, fn) -> + waitsForStateToUpdateAsync = (presenter, fn) -> waitsFor "presenter state to update", 1000, (done) -> disposable = presenter.onDidUpdateState -> disposable.dispose() @@ -1480,9 +1480,9 @@ describe "TextEditorPresenter", -> decoration1 = editor.decorateMarker(marker1, type: 'line', class: 'a') presenter = buildPresenter() marker2 = editor.addMarkerLayer(maintainHistory: true).markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') - decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b') + decoration2 = null - waitsForStateToUpdate presenter + waitsForStateToUpdateAsync presenter, -> decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b') runs -> expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -1490,14 +1490,14 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') + waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([5, 0], 'x') runs -> expect(marker1.isValid()).toBe false expect(lineStateForScreenRow(presenter, 4).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 5).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> editor.undo() + waitsForStateToUpdateAsync presenter, -> editor.undo() runs -> expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -1505,7 +1505,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + waitsForStateToUpdateAsync presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) runs -> expect(lineStateForScreenRow(presenter, 1).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] @@ -1515,7 +1515,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> decoration1.destroy() + waitsForStateToUpdateAsync presenter, -> decoration1.destroy() runs -> expect(lineStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -1524,7 +1524,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> marker2.destroy() + waitsForStateToUpdateAsync presenter, -> marker2.destroy() runs -> expect(lineStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -1688,7 +1688,7 @@ describe "TextEditorPresenter", -> blockDecoration1 = addBlockDecorationBeforeScreenRow(0) blockDecoration2 = addBlockDecorationBeforeScreenRow(1) - waitsForStateToUpdate2 presenter, -> + waitsForStateToUpdateAsync presenter, -> presenter.setBlockDecorationDimensions(blockDecoration1, 0, 30) presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10) @@ -1699,7 +1699,7 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 3)).toBeUndefined() expect(stateForCursor(presenter, 4)).toBeUndefined() - waitsForStateToUpdate2 presenter, -> + waitsForStateToUpdateAsync presenter, -> blockDecoration2.destroy() editor.setCursorBufferPosition([0, 0]) editor.insertNewline() @@ -2216,8 +2216,9 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2) marker = editor.markBufferPosition([2, 2]) - highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') - waitsForStateToUpdate presenter, -> + highlight = null + waitsForStateToUpdateAsync presenter, -> + highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') marker.setBufferRange([[2, 2], [5, 2]]) highlight.flash('b', 500) runs -> @@ -2232,7 +2233,7 @@ describe "TextEditorPresenter", -> flashCount: 1 } - waitsForStateToUpdate presenter, -> highlight.flash('c', 600) + waitsForStateToUpdateAsync presenter, -> highlight.flash('c', 600) runs -> expectValues stateForHighlightInTile(presenter, highlight, 2), { flashClass: 'c' @@ -2479,7 +2480,7 @@ describe "TextEditorPresenter", -> } # Change range - waitsForStateToUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) + waitsForStateToUpdateAsync presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2487,12 +2488,12 @@ describe "TextEditorPresenter", -> } # Valid -> invalid - waitsForStateToUpdate presenter, -> editor.getBuffer().insert([2, 14], 'x') + waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([2, 14], 'x') runs -> expect(stateForOverlay(presenter, decoration)).toBeUndefined() # Invalid -> valid - waitsForStateToUpdate presenter, -> editor.undo() + waitsForStateToUpdateAsync presenter, -> editor.undo() runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2500,7 +2501,7 @@ describe "TextEditorPresenter", -> } # Reverse direction - waitsForStateToUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) + waitsForStateToUpdateAsync presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2508,13 +2509,13 @@ describe "TextEditorPresenter", -> } # Destroy - waitsForStateToUpdate presenter, -> decoration.destroy() + waitsForStateToUpdateAsync presenter, -> decoration.destroy() runs -> expect(stateForOverlay(presenter, decoration)).toBeUndefined() # Add decoration2 = null - waitsForStateToUpdate presenter, -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) + waitsForStateToUpdateAsync presenter, -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) runs -> expectValues stateForOverlay(presenter, decoration2), { item: item @@ -2979,7 +2980,7 @@ describe "TextEditorPresenter", -> presenter.setBlockDecorationDimensions(blockDecoration5, 0, 50) presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) - waitsForStateToUpdate presenter + waitsForStateToUpdateAsync presenter, -> presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) runs -> expect(lineNumberStateForScreenRow(presenter, 0).blockDecorationsHeight).toBe(10) expect(lineNumberStateForScreenRow(presenter, 1).blockDecorationsHeight).toBe(0) @@ -2994,7 +2995,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 10).blockDecorationsHeight).toBe(0) expect(lineNumberStateForScreenRow(presenter, 11).blockDecorationsHeight).toBe(60) - waitsForStateToUpdate presenter, -> + waitsForStateToUpdateAsync presenter, -> blockDecoration1.getMarker().setHeadBufferPosition([1, 0]) blockDecoration2.getMarker().setHeadBufferPosition([5, 0]) blockDecoration3.getMarker().setHeadBufferPosition([9, 0]) @@ -3013,7 +3014,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 10).blockDecorationsHeight).toBe(0) expect(lineNumberStateForScreenRow(presenter, 11).blockDecorationsHeight).toBe(60) - waitsForStateToUpdate presenter, -> + waitsForStateToUpdateAsync presenter, -> blockDecoration1.destroy() blockDecoration3.destroy() @@ -3045,14 +3046,14 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') + waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([5, 0], 'x') runs -> expect(marker1.isValid()).toBe false expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> editor.undo() + waitsForStateToUpdateAsync presenter, -> editor.undo() runs -> expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -3060,7 +3061,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + waitsForStateToUpdateAsync presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) runs -> expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] @@ -3070,7 +3071,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> decoration1.destroy() + waitsForStateToUpdateAsync presenter, -> decoration1.destroy() runs -> expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -3079,7 +3080,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdate presenter, -> marker2.destroy() + waitsForStateToUpdateAsync presenter, -> marker2.destroy() runs -> expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -3297,7 +3298,7 @@ describe "TextEditorPresenter", -> expect(decorationState[decoration3.id].item).toBe decorationItem expect(decorationState[decoration3.id].class).toBe 'test-class' - waitsForStateToUpdate presenter, -> blockDecoration1.destroy() + waitsForStateToUpdateAsync presenter, -> blockDecoration1.destroy() runs -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') expect(decorationState[decoration1.id]).toBeUndefined() @@ -3416,7 +3417,7 @@ describe "TextEditorPresenter", -> gutterName: 'test-gutter-2' class: 'new-test-class' item: decorationItem - waitsForStateToUpdate presenter, -> decoration1.setProperties(newDecorationParams) + waitsForStateToUpdateAsync presenter, -> decoration1.setProperties(newDecorationParams) runs -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') @@ -3470,7 +3471,7 @@ describe "TextEditorPresenter", -> marker4 = editor.markBufferRange([[0, 0], [1, 0]]) decoration4 = null - waitsForStateToUpdate2 presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams) + waitsForStateToUpdateAsync presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams) runs -> expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) @@ -3537,7 +3538,7 @@ describe "TextEditorPresenter", -> blockDecorationsHeight = Math.round(35.8 + 100.3 + 95.2) expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe(linesHeight + blockDecorationsHeight) - waitsForStateToUpdate presenter, -> blockDecoration3.destroy() + waitsForStateToUpdateAsync presenter, -> blockDecoration3.destroy() runs -> blockDecorationsHeight = Math.round(35.8 + 100.3) expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe(linesHeight + blockDecorationsHeight) From 9fa766e01ac928ab7b9de682fa5459bbbb92c553 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 15:13:10 -0500 Subject: [PATCH 47/66] Don't use synchronous updates anymore. --- spec/text-editor-presenter-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index c3abeb062..b0eb6d09b 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -20,7 +20,6 @@ describe "TextEditorPresenter", -> buffer = new TextBuffer(filePath: require.resolve('./fixtures/sample.js')) editor = atom.workspace.buildTextEditor({buffer}) - editor.setUpdatedSynchronously(true) waitsForPromise -> buffer.load() afterEach -> From 82860a12a08eabe50812126e1c41e74db5f1cc8f Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 16:35:10 -0500 Subject: [PATCH 48/66] Fix waitsForStateToUpdate proper like. --- spec/text-editor-presenter-spec.coffee | 84 +++++++++++++------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index b0eb6d09b..5e51c7176 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -90,19 +90,12 @@ describe "TextEditorPresenter", -> expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn) - waitsForStateToUpdateAsync = (presenter, fn) -> - waitsFor "presenter state to update", 1000, (done) -> - disposable = presenter.onDidUpdateState -> - disposable.dispose() - process.nextTick(done) - fn?() - waitsForStateToUpdate = (presenter, fn) -> waitsFor "presenter state to update", 1000, (done) -> - fn?() disposable = presenter.onDidUpdateState -> disposable.dispose() process.nextTick(done) + fn?() tiledContentContract = (stateFn) -> it "contains states for tiles that are visible on screen", -> @@ -1481,7 +1474,7 @@ describe "TextEditorPresenter", -> marker2 = editor.addMarkerLayer(maintainHistory: true).markBufferRange([[4, 0], [6, 2]], invalidate: 'touch') decoration2 = null - waitsForStateToUpdateAsync presenter, -> decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b') + waitsForStateToUpdate presenter, -> decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b') runs -> expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -1489,14 +1482,14 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([5, 0], 'x') + waitsForStateToUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') runs -> expect(marker1.isValid()).toBe false expect(lineStateForScreenRow(presenter, 4).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 5).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> editor.undo() + waitsForStateToUpdate presenter, -> editor.undo() runs -> expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -1504,7 +1497,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + waitsForStateToUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) runs -> expect(lineStateForScreenRow(presenter, 1).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] @@ -1514,7 +1507,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> decoration1.destroy() + waitsForStateToUpdate presenter, -> decoration1.destroy() runs -> expect(lineStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -1523,7 +1516,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> marker2.destroy() + waitsForStateToUpdate presenter, -> marker2.destroy() runs -> expect(lineStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -1687,7 +1680,7 @@ describe "TextEditorPresenter", -> blockDecoration1 = addBlockDecorationBeforeScreenRow(0) blockDecoration2 = addBlockDecorationBeforeScreenRow(1) - waitsForStateToUpdateAsync presenter, -> + waitsForStateToUpdate presenter, -> presenter.setBlockDecorationDimensions(blockDecoration1, 0, 30) presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10) @@ -1698,7 +1691,7 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 3)).toBeUndefined() expect(stateForCursor(presenter, 4)).toBeUndefined() - waitsForStateToUpdateAsync presenter, -> + waitsForStateToUpdate presenter, -> blockDecoration2.destroy() editor.setCursorBufferPosition([0, 0]) editor.insertNewline() @@ -2157,31 +2150,40 @@ describe "TextEditorPresenter", -> } # becoming empty - waitsForStateToUpdate presenter, -> editor.getSelections()[1].clear(autoscroll: false) + runs -> + editor.getSelections()[1].clear(autoscroll: false) + waitsForStateToUpdate presenter runs -> expectUndefinedStateForSelection(presenter, 1) # becoming non-empty - waitsForStateToUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) + runs -> + editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false) + waitsForStateToUpdate presenter runs -> expectValues stateForSelectionInTile(presenter, 1, 2), { regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}] } # moving out of view - waitsForStateToUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false) + runs -> + editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false) + waitsForStateToUpdate presenter runs -> expectUndefinedStateForSelection(presenter, 1) # adding - waitsForStateToUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false) + runs -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false) + waitsForStateToUpdate presenter runs -> expectValues stateForSelectionInTile(presenter, 2, 0), { regions: [{top: 10, left: 4 * 10, width: 2 * 10, height: 10}] } # moving added selection - waitsForStateToUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false) + runs -> + editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false) + waitsForStateToUpdate presenter destroyedSelection = null runs -> @@ -2216,7 +2218,7 @@ describe "TextEditorPresenter", -> marker = editor.markBufferPosition([2, 2]) highlight = null - waitsForStateToUpdateAsync presenter, -> + waitsForStateToUpdate presenter, -> highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a') marker.setBufferRange([[2, 2], [5, 2]]) highlight.flash('b', 500) @@ -2232,7 +2234,7 @@ describe "TextEditorPresenter", -> flashCount: 1 } - waitsForStateToUpdateAsync presenter, -> highlight.flash('c', 600) + waitsForStateToUpdate presenter, -> highlight.flash('c', 600) runs -> expectValues stateForHighlightInTile(presenter, highlight, 2), { flashClass: 'c' @@ -2479,7 +2481,7 @@ describe "TextEditorPresenter", -> } # Change range - waitsForStateToUpdateAsync presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) + waitsForStateToUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]]) runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2487,12 +2489,12 @@ describe "TextEditorPresenter", -> } # Valid -> invalid - waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([2, 14], 'x') + waitsForStateToUpdate presenter, -> editor.getBuffer().insert([2, 14], 'x') runs -> expect(stateForOverlay(presenter, decoration)).toBeUndefined() # Invalid -> valid - waitsForStateToUpdateAsync presenter, -> editor.undo() + waitsForStateToUpdate presenter, -> editor.undo() runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2500,7 +2502,7 @@ describe "TextEditorPresenter", -> } # Reverse direction - waitsForStateToUpdateAsync presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) + waitsForStateToUpdate presenter, -> marker.setBufferRange([[2, 13], [4, 6]], reversed: true) runs -> expectValues stateForOverlay(presenter, decoration), { item: item @@ -2508,13 +2510,13 @@ describe "TextEditorPresenter", -> } # Destroy - waitsForStateToUpdateAsync presenter, -> decoration.destroy() + waitsForStateToUpdate presenter, -> decoration.destroy() runs -> expect(stateForOverlay(presenter, decoration)).toBeUndefined() # Add decoration2 = null - waitsForStateToUpdateAsync presenter, -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) + waitsForStateToUpdate presenter, -> decoration2 = editor.decorateMarker(marker, {type: 'overlay', item}) runs -> expectValues stateForOverlay(presenter, decoration2), { item: item @@ -2979,7 +2981,7 @@ describe "TextEditorPresenter", -> presenter.setBlockDecorationDimensions(blockDecoration5, 0, 50) presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) - waitsForStateToUpdateAsync presenter, -> presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) + waitsForStateToUpdate presenter, -> presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) runs -> expect(lineNumberStateForScreenRow(presenter, 0).blockDecorationsHeight).toBe(10) expect(lineNumberStateForScreenRow(presenter, 1).blockDecorationsHeight).toBe(0) @@ -2994,7 +2996,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 10).blockDecorationsHeight).toBe(0) expect(lineNumberStateForScreenRow(presenter, 11).blockDecorationsHeight).toBe(60) - waitsForStateToUpdateAsync presenter, -> + waitsForStateToUpdate presenter, -> blockDecoration1.getMarker().setHeadBufferPosition([1, 0]) blockDecoration2.getMarker().setHeadBufferPosition([5, 0]) blockDecoration3.getMarker().setHeadBufferPosition([9, 0]) @@ -3013,7 +3015,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 10).blockDecorationsHeight).toBe(0) expect(lineNumberStateForScreenRow(presenter, 11).blockDecorationsHeight).toBe(60) - waitsForStateToUpdateAsync presenter, -> + waitsForStateToUpdate presenter, -> blockDecoration1.destroy() blockDecoration3.destroy() @@ -3045,14 +3047,14 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> editor.getBuffer().insert([5, 0], 'x') + waitsForStateToUpdate presenter, -> editor.getBuffer().insert([5, 0], 'x') runs -> expect(marker1.isValid()).toBe false expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 5).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> editor.undo() + waitsForStateToUpdate presenter, -> editor.undo() runs -> expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b'] @@ -3060,7 +3062,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['a', 'b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) + waitsForStateToUpdate presenter, -> marker1.setBufferRange([[2, 0], [4, 2]]) runs -> expect(lineNumberStateForScreenRow(presenter, 1).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toEqual ['a'] @@ -3070,7 +3072,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> decoration1.destroy() + waitsForStateToUpdate presenter, -> decoration1.destroy() runs -> expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -3079,7 +3081,7 @@ describe "TextEditorPresenter", -> expect(lineNumberStateForScreenRow(presenter, 6).decorationClasses).toEqual ['b'] expect(lineNumberStateForScreenRow(presenter, 7).decorationClasses).toBeNull() - waitsForStateToUpdateAsync presenter, -> marker2.destroy() + waitsForStateToUpdate presenter, -> marker2.destroy() runs -> expect(lineNumberStateForScreenRow(presenter, 2).decorationClasses).toBeNull() expect(lineNumberStateForScreenRow(presenter, 3).decorationClasses).toBeNull() @@ -3297,7 +3299,7 @@ describe "TextEditorPresenter", -> expect(decorationState[decoration3.id].item).toBe decorationItem expect(decorationState[decoration3.id].class).toBe 'test-class' - waitsForStateToUpdateAsync presenter, -> blockDecoration1.destroy() + waitsForStateToUpdate presenter, -> blockDecoration1.destroy() runs -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') expect(decorationState[decoration1.id]).toBeUndefined() @@ -3416,7 +3418,7 @@ describe "TextEditorPresenter", -> gutterName: 'test-gutter-2' class: 'new-test-class' item: decorationItem - waitsForStateToUpdateAsync presenter, -> decoration1.setProperties(newDecorationParams) + waitsForStateToUpdate presenter, -> decoration1.setProperties(newDecorationParams) runs -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') @@ -3470,7 +3472,7 @@ describe "TextEditorPresenter", -> marker4 = editor.markBufferRange([[0, 0], [1, 0]]) decoration4 = null - waitsForStateToUpdateAsync presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams) + waitsForStateToUpdate presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams) runs -> expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'}) @@ -3537,7 +3539,7 @@ describe "TextEditorPresenter", -> blockDecorationsHeight = Math.round(35.8 + 100.3 + 95.2) expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe(linesHeight + blockDecorationsHeight) - waitsForStateToUpdateAsync presenter, -> blockDecoration3.destroy() + waitsForStateToUpdate presenter, -> blockDecoration3.destroy() runs -> blockDecorationsHeight = Math.round(35.8 + 100.3) expect(getStylesForGutterWithName(presenter, 'line-number').scrollHeight).toBe(linesHeight + blockDecorationsHeight) From cc3f6b888f567f192dae7756c49ec2f838588e3e Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 12 Feb 2016 16:35:16 -0500 Subject: [PATCH 49/66] Don't need to duplicate this line. --- spec/text-editor-presenter-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 5e51c7176..c353e21c0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2979,7 +2979,6 @@ describe "TextEditorPresenter", -> presenter.setBlockDecorationDimensions(blockDecoration4, 0, 35) presenter.setBlockDecorationDimensions(blockDecoration4, 0, 40) presenter.setBlockDecorationDimensions(blockDecoration5, 0, 50) - presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) waitsForStateToUpdate presenter, -> presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60) runs -> From 22c9fe7cb7e8fdc76a98096c0f3212ed21ab03aa Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 12 Feb 2016 14:06:06 -0800 Subject: [PATCH 50/66] :fire: trailing white space --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f7869f9af..248ee7e6a 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -648,7 +648,7 @@ class AtomEnvironment extends Model @registerDefaultTargetForKeymaps() @packages.loadPackages() - + @document.body.appendChild(@views.getView(@workspace)) @watchProjectPath() From 427dba57adc771032ff2c978a2d59cf3d8e8817a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 12 Feb 2016 14:07:21 -0800 Subject: [PATCH 51/66] Remove unused StorageFolder::store method (moved state to IndexedDB) --- src/storage-folder.coffee | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index ff3474198..06beae56a 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -11,11 +11,6 @@ class StorageFolder fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8') - store: (name, object) -> - return unless @path? - - fs.writeFile(@pathForKey(name), JSON.stringify(object), 'utf8') - load: (name) -> return unless @path? From 24dc4c6c738c5b5d49506461f38b501b702a99ac Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 11 Feb 2016 19:56:50 -0800 Subject: [PATCH 52/66] Add command-line argument to clear state in IndexedDB --- src/browser/main.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/browser/main.coffee b/src/browser/main.coffee index bbce1d87f..c1df3455f 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -123,6 +123,7 @@ parseCommandLine = -> options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') options.string('user-data-dir') + options.boolean('clear-state').describe('clear-state', 'Delete all Atom environment state.') args = options.argv @@ -146,6 +147,7 @@ parseCommandLine = -> socketPath = args['socket-path'] userDataDir = args['user-data-dir'] profileStartup = args['profile-startup'] + clearState = args['clear-state'] urlsToOpen = [] devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getHomeDir(), 'github', 'atom') setPortable = args.portable @@ -169,6 +171,7 @@ parseCommandLine = -> {resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, - logFile, socketPath, userDataDir, profileStartup, timeout, setPortable} + logFile, socketPath, userDataDir, profileStartup, timeout, setPortable, + clearState} start() From 6b24f4bfa7779aa0fbeef4a6100bf309802c6fbe Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 12 Feb 2016 18:36:12 -0800 Subject: [PATCH 53/66] :memo: Fix atom.workspace.open split parameter mismatch --- src/workspace.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index ebaf1b337..79757a43b 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -394,7 +394,7 @@ class Workspace extends Model # initially. Defaults to `0`. # * `initialColumn` A {Number} indicating which column to move the cursor to # initially. Defaults to `0`. - # * `split` Either 'left', 'right', 'top' or 'bottom'. + # * `split` Either 'left', 'right', 'up' or 'down'. # If 'left', the item will be opened in leftmost pane of the current active pane's row. # If 'right', the item will be opened in the rightmost pane of the current active pane's row. # If 'up', the item will be opened in topmost pane of the current active pane's row. From 0b13cb00e1f299f3c5d7f7b81fc15d6cd7d5a8fe Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 12 Feb 2016 18:45:05 -0800 Subject: [PATCH 54/66] :memo: Make the atom.workspace.open split documentation match behavior --- src/workspace.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 79757a43b..79cfb3e8e 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -396,9 +396,9 @@ class Workspace extends Model # initially. Defaults to `0`. # * `split` Either 'left', 'right', 'up' or 'down'. # If 'left', the item will be opened in leftmost pane of the current active pane's row. - # If 'right', the item will be opened in the rightmost pane of the current active pane's row. - # If 'up', the item will be opened in topmost pane of the current active pane's row. - # If 'down', the item will be opened in the bottommost pane of the current active pane's row. + # If 'right', the item will be opened in the rightmost pane of the current active pane's row. If only one pane exists in the row, a new pane will be created. + # If 'up', the item will be opened in topmost pane of the current active pane's column. + # If 'down', the item will be opened in the bottommost pane of the current active pane's column. If only one pane exists in the column, a new pane will be created. # * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on # containing pane. Defaults to `true`. # * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem} From 57ea5c0fc400cb81c22c1c2b2e8acf57eb36157e Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 12 Feb 2016 18:54:12 -0800 Subject: [PATCH 55/66] Fix typo in function call --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 0a5cca4c3..6c3612e5e 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -713,7 +713,7 @@ class Pane extends Model if @parent.orientation is 'vertical' bottommostSibling = last(@parent.children) if bottommostSibling instanceof PaneAxis - @splitRight() + @splitDown() else bottommostSibling else From f8ae09b1122ded5de3d4958630b485a2e1fd82a0 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Sun, 14 Feb 2016 15:10:07 -0800 Subject: [PATCH 56/66] Register Atom for file associations in Windows #6177 #4893 #6860 --- src/browser/squirrel-update.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 3660158fc..f9684ce49 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -20,6 +20,7 @@ else fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom' directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom' backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom' +applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe' environmentKeyPath = 'HKCU\\Environment' # Spawn a command and invoke the callback when it completes with an error @@ -64,6 +65,10 @@ installContextMenu = (callback) -> args.push('/f') spawnReg(args, callback) + installFileHandler = (callback) -> + args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""] + addToRegistry(args, callback) + installMenu = (keyPath, arg, callback) -> args = [keyPath, '/ve', '/d', 'Open with Atom'] addToRegistry args, -> @@ -74,7 +79,8 @@ installContextMenu = (callback) -> installMenu fileKeyPath, '%1', -> installMenu directoryKeyPath, '%1', -> - installMenu(backgroundKeyPath, '%V', callback) + installMenu backgroundKeyPath, '%V', -> + installFileHandler(callback) isAscii = (text) -> index = 0 @@ -124,7 +130,8 @@ uninstallContextMenu = (callback) -> deleteFromRegistry fileKeyPath, -> deleteFromRegistry directoryKeyPath, -> - deleteFromRegistry(backgroundKeyPath, callback) + deleteFromRegistry backgroundKeyPath, -> + deleteFromRegistry(applicationsKeyPath, callback) # Add atom and apm to the PATH # From 2e8569d7b38abaa49fb583eecfb711c375b67e1e Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 15 Feb 2016 17:03:09 -0500 Subject: [PATCH 57/66] Port failing tests. Bring the failing tests over from https://github.com/atom/atom/pull/10758 and https://github.com/atom/atom/pull/10797. --- spec/git-repository-async-spec.js | 48 +++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index dfc3d5803..9999afc63 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -338,10 +338,10 @@ describe('GitRepositoryAsync', () => { }) describe('.refreshStatus()', () => { - let newPath, modifiedPath, cleanPath + let newPath, modifiedPath, cleanPath, workingDirectory beforeEach(() => { - const workingDirectory = copyRepository() + workingDirectory = copyRepository() repo = GitRepositoryAsync.open(workingDirectory) modifiedPath = path.join(workingDirectory, 'file.txt') newPath = path.join(workingDirectory, 'untracked.txt') @@ -362,7 +362,7 @@ describe('GitRepositoryAsync', () => { describe('in a repository with submodules', () => { beforeEach(() => { - const workingDirectory = copySubmoduleRepository() + workingDirectory = copySubmoduleRepository() repo = GitRepositoryAsync.open(workingDirectory) modifiedPath = path.join(workingDirectory, 'jstips', 'README.md') newPath = path.join(workingDirectory, 'You-Dont-Need-jQuery', 'untracked.txt') @@ -380,6 +380,48 @@ describe('GitRepositoryAsync', () => { expect(repo.isStatusModified(await repo.getCachedPathStatus(modifiedPath))).toBe(true) }) }) + + it('caches the proper statuses when a subdir is open', async () => { + const subDir = path.join(workingDirectory, 'dir') + fs.mkdirSync(subDir) + + const filePath = path.join(subDir, 'b.txt') + fs.writeFileSync(filePath, '') + + atom.project.setPaths([subDir]) + + await atom.workspace.open('b.txt') + + const repo = atom.project.getRepositories()[0].async + + await repo.refreshStatus() + + const status = await repo.getCachedPathStatus(filePath) + expect(repo.isStatusModified(status)).toBe(false) + expect(repo.isStatusNew(status)).toBe(false) + }) + + it('caches the proper statuses when multiple project are open', async () => { + const otherWorkingDirectory = copyRepository() + + atom.project.setPaths([workingDirectory, otherWorkingDirectory]) + + await atom.workspace.open('b.txt') + + const repo = atom.project.getRepositories()[0].async + + await repo.refreshStatus() + + const subDir = path.join(workingDirectory, 'dir') + fs.mkdirSync(subDir) + + const filePath = path.join(subDir, 'b.txt') + fs.writeFileSync(filePath, 'some content!') + + const status = await repo.getCachedPathStatus(filePath) + expect(repo.isStatusModified(status)).toBe(true) + expect(repo.isStatusNew(status)).toBe(false) + }) }) describe('.isProjectAtRoot()', () => { From a87aac00e4d1efd8afe5e5631e8ab98585ac8cc3 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 15 Feb 2016 17:04:03 -0500 Subject: [PATCH 58/66] Port the fixes too. --- src/git-repository-async.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 38792e02e..cf9f9d6fe 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -456,7 +456,10 @@ export default class GitRepositoryAsync { // information. getDirectoryStatus (directoryPath) { return this.relativizeToWorkingDirectory(directoryPath) - .then(relativePath => this._getStatus([relativePath])) + .then(relativePath => { + const pathspec = relativePath + '/**' + return this._getStatus([pathspec]) + }) .then(statuses => { return Promise.all(statuses.map(s => s.statusBit())).then(bits => { return bits @@ -800,7 +803,7 @@ export default class GitRepositoryAsync { } return Promise.all(projectPathsPromises) - .then(paths => paths.filter(p => p.length > 0)) + .then(paths => paths.map(p => p.length > 0 ? p + '/**' : '*')) .then(projectPaths => { return this._getStatus(projectPaths.length > 0 ? projectPaths : null) }) @@ -1032,7 +1035,7 @@ export default class GitRepositoryAsync { return this.getRepo() .then(repo => { const opts = { - flags: Git.Status.OPT.INCLUDE_UNTRACKED | Git.Status.OPT.RECURSE_UNTRACKED_DIRS | Git.Status.OPT.DISABLE_PATHSPEC_MATCH + flags: Git.Status.OPT.INCLUDE_UNTRACKED | Git.Status.OPT.RECURSE_UNTRACKED_DIRS } if (paths) { From f0a179fdb57a4de6e915dd5541c5f8feeb0a63bf Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 15 Feb 2016 17:19:32 -0500 Subject: [PATCH 59/66] Add the decoration after subscribing to state updates Same fixe as #10792. --- spec/text-editor-presenter-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index c353e21c0..57c674033 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1336,9 +1336,9 @@ describe "TextEditorPresenter", -> presenter = buildPresenter() blockDecoration2 = addBlockDecorationBeforeScreenRow(3) blockDecoration3 = addBlockDecorationBeforeScreenRow(7) - blockDecoration4 = addBlockDecorationAfterScreenRow(7) + blockDecoration4 = null - waitsForStateToUpdate presenter + waitsForStateToUpdate presenter, blockDecoration4 = addBlockDecorationAfterScreenRow(7) runs -> expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([blockDecoration1]) expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([]) From 47459948cff0f8da55197094b1d4fe941aabdceb Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 15 Feb 2016 21:28:25 -0800 Subject: [PATCH 60/66] =?UTF-8?q?Clear=20state=20in=20indexedDB=20if=20?= =?UTF-8?q?=E2=80=98clear-state=E2=80=99=20command-line=20flag=20is=20pass?= =?UTF-8?q?ed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom-environment.coffee | 6 ++++-- src/browser/atom-application.coffee | 17 +++++++++-------- src/browser/atom-window.coffee | 1 + 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f7869f9af..cdb22b40d 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -122,13 +122,15 @@ class AtomEnvironment extends Model {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @loadTime = null - {devMode, safeMode, resourcePath} = @getLoadSettings() + {devMode, safeMode, resourcePath, clearState} = @getLoadSettings() @emitter = new Emitter @disposables = new CompositeDisposable @stateStore = new StateStore('AtomEnvironments', 1) + @stateStore.clear() if clearState + @deserializers = new DeserializerManager(this) @deserializeTimings = {} @@ -648,7 +650,7 @@ class AtomEnvironment extends Model @registerDefaultTargetForKeymaps() @packages.loadPackages() - + @document.body.appendChild(@views.getView(@workspace)) @watchProjectPath() diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 5ff24c458..891caf19d 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -65,7 +65,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout} = options + {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout, clearState} = options @socketPath = null if options.test @@ -89,16 +89,16 @@ class AtomApplication else @loadState(options) or @openPath(options) - openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout}) -> + openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearState}) -> if test @runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup}) + @openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearState}) else if urlsToOpen.length > 0 @openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen else # Always open a editor window if this is the first instance of Atom. - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup}) + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearState}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -387,8 +387,8 @@ class AtomApplication # :safeMode - Boolean to control the opened window's safe mode. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window} = {}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearState} = {}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearState}) # Public: Opens multiple paths, in existing windows if possible. # @@ -400,9 +400,10 @@ class AtomApplication # :safeMode - Boolean to control the opened window's safe mode. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window}={}) -> + openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearState}={}) -> devMode = Boolean(devMode) safeMode = Boolean(safeMode) + clearState = Boolean(clearState) locationsToOpen = (@locationForPathToOpen(pathToOpen, executedFrom) for pathToOpen in pathsToOpen) pathsToOpen = (locationToOpen.pathToOpen for locationToOpen in locationsToOpen) @@ -435,7 +436,7 @@ class AtomApplication windowInitializationScript ?= require.resolve('../initialize-application-window') resourcePath ?= @resourcePath windowDimensions ?= @getDimensionsForNewWindow() - openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup}) + openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearState}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 20ba2ad5c..35ccabb8a 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -50,6 +50,7 @@ class AtomWindow loadSettings.safeMode ?= false loadSettings.atomHome = process.env.ATOM_HOME loadSettings.firstLoad = true + loadSettings.clearState ?= false # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec From 702af8cd1635a016c1a374d621013c32f96bc292 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 15 Feb 2016 21:46:25 -0800 Subject: [PATCH 61/66] Use pre-released text-buffer version 8.3.1-0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ccae78a3..38956f362 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.3.0-0", + "text-buffer": "8.3.1-0", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From 5d9c5c51d35adb0b0047ba8b309611c8d978bbf4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 16 Feb 2016 10:16:10 -0500 Subject: [PATCH 62/66] We might wanna log the output. --- build/tasks/spec-task.coffee | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 892c92696..19b553412 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -86,7 +86,7 @@ module.exports = (grunt) -> packageSpecQueue.concurrency = Math.max(1, concurrency - 1) packageSpecQueue.drain = -> callback(null, failedPackages) - runCoreSpecs = (callback) -> + runCoreSpecs = (callback, logOutput = false) -> appPath = getAppPath() resourcePath = process.cwd() coreSpecsPath = path.resolve('spec') @@ -130,11 +130,17 @@ module.exports = (grunt) -> else async.parallel + # If we're just running the core specs then we won't have any output to + # indicate the tests actually *are* running. This upsets Travis: + # https://github.com/atom/atom/issues/10837. So pass the test output + # through. + runCoreSpecsWithLogging = (callback) -> runCoreSpecs(callback, true) + specs = if process.env.ATOM_SPECS_TASK is 'packages' [runPackageSpecs] else if process.env.ATOM_SPECS_TASK is 'core' - [runCoreSpecs] + [runCoreSpecsWithLogging] else [runCoreSpecs, runPackageSpecs] From a89257d4749403f3f6b42f3b2cc4040749b8d52c Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 16 Feb 2016 10:16:21 -0500 Subject: [PATCH 63/66] Just inherit stdio if we're logging. --- build/tasks/spec-task.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index 19b553412..e3fa105ac 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -109,6 +109,9 @@ module.exports = (grunt) -> ATOM_INTEGRATION_TESTS_ENABLED: true ) + if logOutput + options.opts.stdio = 'inherit' + grunt.log.ok "Launching core specs." spawn options, (error, results, code) -> if process.platform is 'win32' From 7f239560f8efafaed1514fde181b215cb226963e Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 16 Feb 2016 10:16:39 -0500 Subject: [PATCH 64/66] Depending on the options passed through, we might not have stdout and stderr. --- build/tasks/task-helpers.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/tasks/task-helpers.coffee b/build/tasks/task-helpers.coffee index d24cdec77..b42b4dd15 100644 --- a/build/tasks/task-helpers.coffee +++ b/build/tasks/task-helpers.coffee @@ -52,8 +52,10 @@ module.exports = (grunt) -> stderr = [] error = null proc = childProcess.spawn(options.cmd, options.args, options.opts) - proc.stdout.on 'data', (data) -> stdout.push(data.toString()) - proc.stderr.on 'data', (data) -> stderr.push(data.toString()) + if proc.stdout? + proc.stdout.on 'data', (data) -> stdout.push(data.toString()) + if proc.stderr? + proc.stderr.on 'data', (data) -> stderr.push(data.toString()) proc.on 'error', (processError) -> error ?= processError proc.on 'close', (exitCode, signal) -> error ?= new Error(signal) if exitCode isnt 0 From 083f577889a232909dc2117aa18c3efe1dc674fc Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 16 Feb 2016 10:28:30 -0800 Subject: [PATCH 65/66] =?UTF-8?q?Use=20more=20descriptive=20flag=20for=20c?= =?UTF-8?q?learing=20state=20-=20=E2=80=98clear-window-state=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom-environment.coffee | 4 ++-- src/browser/atom-application.coffee | 18 +++++++++--------- src/browser/atom-window.coffee | 2 +- src/browser/main.coffee | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index cdb22b40d..ed36f5da2 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -122,14 +122,14 @@ class AtomEnvironment extends Model {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @loadTime = null - {devMode, safeMode, resourcePath, clearState} = @getLoadSettings() + {devMode, safeMode, resourcePath, clearWindowState} = @getLoadSettings() @emitter = new Emitter @disposables = new CompositeDisposable @stateStore = new StateStore('AtomEnvironments', 1) - @stateStore.clear() if clearState + @stateStore.clear() if clearWindowState @deserializers = new DeserializerManager(this) @deserializeTimings = {} diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 891caf19d..e889840e5 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -65,7 +65,7 @@ class AtomApplication exit: (status) -> app.exit(status) constructor: (options) -> - {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout, clearState} = options + {@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout, clearWindowState} = options @socketPath = null if options.test @@ -89,16 +89,16 @@ class AtomApplication else @loadState(options) or @openPath(options) - openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearState}) -> + openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState}) -> if test @runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearState}) + @openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState}) else if urlsToOpen.length > 0 @openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen else # Always open a editor window if this is the first instance of Atom. - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearState}) + @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -387,8 +387,8 @@ class AtomApplication # :safeMode - Boolean to control the opened window's safe mode. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearState} = {}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearState}) + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState} = {}) -> + @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState}) # Public: Opens multiple paths, in existing windows if possible. # @@ -400,10 +400,10 @@ class AtomApplication # :safeMode - Boolean to control the opened window's safe mode. # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. - openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearState}={}) -> + openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState}={}) -> devMode = Boolean(devMode) safeMode = Boolean(safeMode) - clearState = Boolean(clearState) + clearWindowState = Boolean(clearWindowState) locationsToOpen = (@locationForPathToOpen(pathToOpen, executedFrom) for pathToOpen in pathsToOpen) pathsToOpen = (locationToOpen.pathToOpen for locationToOpen in locationsToOpen) @@ -436,7 +436,7 @@ class AtomApplication windowInitializationScript ?= require.resolve('../initialize-application-window') resourcePath ?= @resourcePath windowDimensions ?= @getDimensionsForNewWindow() - openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearState}) + openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 35ccabb8a..0c0f8f919 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -50,7 +50,7 @@ class AtomWindow loadSettings.safeMode ?= false loadSettings.atomHome = process.env.ATOM_HOME loadSettings.firstLoad = true - loadSettings.clearState ?= false + loadSettings.clearWindowState ?= false # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec diff --git a/src/browser/main.coffee b/src/browser/main.coffee index c1df3455f..c0613fb09 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -123,7 +123,7 @@ parseCommandLine = -> options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') options.string('socket-path') options.string('user-data-dir') - options.boolean('clear-state').describe('clear-state', 'Delete all Atom environment state.') + options.boolean('clear-window-state').describe('clear-window-state', 'Delete all Atom environment state.') args = options.argv @@ -147,7 +147,7 @@ parseCommandLine = -> socketPath = args['socket-path'] userDataDir = args['user-data-dir'] profileStartup = args['profile-startup'] - clearState = args['clear-state'] + clearWindowState = args['clear-window-state'] urlsToOpen = [] devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getHomeDir(), 'github', 'atom') setPortable = args.portable @@ -172,6 +172,6 @@ parseCommandLine = -> {resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, socketPath, userDataDir, profileStartup, timeout, setPortable, - clearState} + clearWindowState} start() From c691dd05c57322cffd25f58bb4fec57fb9e3b31c Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 16 Feb 2016 11:57:35 -0800 Subject: [PATCH 66/66] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38956f362..3977cb806 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.3.1-0", + "text-buffer": "8.3.1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0"