Merge pull request #11060 from atom/as-serialize-history-without-snapshots

Serialize MarkerLayers only on quit
This commit is contained in:
Antonio Scandurra
2016-03-07 12:49:30 +01:00
11 changed files with 46 additions and 28 deletions

View File

@@ -54,7 +54,7 @@
"service-hub": "^0.7.0",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "8.3.2",
"text-buffer": "8.4.1",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"yargs": "^3.23.0"

View File

@@ -185,12 +185,12 @@ describe "AtomEnvironment", ->
keydown = new KeyboardEvent('keydown')
atom.document.dispatchEvent(keydown)
advanceClock atom.saveStateDebounceInterval
expect(atom.saveState).toHaveBeenCalled()
expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false})
mousedown = new MouseEvent('mousedown')
atom.document.dispatchEvent(mousedown)
advanceClock atom.saveStateDebounceInterval
expect(atom.saveState).toHaveBeenCalled()
expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false})
describe "openInitialEmptyEditorIfNecessary", ->
describe "when there are no paths set", ->

View File

@@ -541,7 +541,7 @@ describe('GitRepositoryAsync', () => {
await atom.workspace.open('file.txt')
project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
project2.deserialize(atom.project.serialize(), atom.deserializers)
project2.deserialize(atom.project.serialize({isUnloading: true}))
const repo = project2.getRepositories()[0].async
waitsForPromise(() => repo.refreshStatus())

View File

@@ -347,7 +347,7 @@ describe "GitRepository", ->
runs ->
project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
project2.deserialize(atom.project.serialize(), atom.deserializers)
project2.deserialize(atom.project.serialize({isUnloading: false}))
buffer = project2.getBuffers()[0]
waitsFor ->

View File

@@ -37,7 +37,7 @@ describe "Project", ->
expect(atom.project.getBuffers().length).toBe 1
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))
expect(deserializedProject.getBuffers().length).toBe 0
it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", ->
@@ -47,7 +47,7 @@ describe "Project", ->
runs ->
expect(atom.project.getBuffers().length).toBe 1
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))
expect(deserializedProject.getBuffers().length).toBe 1
deserializedProject.getBuffers()[0].destroy()
@@ -64,7 +64,7 @@ describe "Project", ->
expect(atom.project.getBuffers().length).toBe 1
fs.mkdirSync(pathToOpen)
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))
expect(deserializedProject.getBuffers().length).toBe 0
it "does not deserialize buffers when their path is inaccessible", ->
@@ -78,9 +78,26 @@ describe "Project", ->
expect(atom.project.getBuffers().length).toBe 1
fs.chmodSync(pathToOpen, '000')
deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
deserializedProject.deserialize(atom.project.serialize(), atom.deserializers)
deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))
expect(deserializedProject.getBuffers().length).toBe 0
it "serializes marker layers only if Atom is quitting", ->
waitsForPromise ->
atom.workspace.open('a')
runs ->
bufferA = atom.project.getBuffers()[0]
layerA = bufferA.addMarkerLayer(maintainHistory: true)
markerA = layerA.markPosition([0, 3])
notQuittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
notQuittingProject.deserialize(atom.project.serialize({isUnloading: false}))
expect(notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).toBeUndefined()
quittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm})
quittingProject.deserialize(atom.project.serialize({isUnloading: true}))
expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).not.toBeUndefined()
describe "when an editor is saved and the project has no path", ->
it "sets the project's path to the saved file's parent directory", ->
tempFile = temp.openSync().path

View File

@@ -55,6 +55,11 @@ describe "WindowEventHandler", ->
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
spyOn(ipcRenderer, 'send')
it "saves AtomEnvironment's state with the {isUnloading: true} option", ->
spyOn(atom, 'saveState')
window.dispatchEvent(new CustomEvent('beforeunload'))
expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true})
describe "when pane items are modified", ->
editor = null
beforeEach ->

View File

@@ -22,11 +22,11 @@ describe "Workspace", ->
describe "serialization", ->
simulateReload = ->
workspaceState = atom.workspace.serialize()
projectState = atom.project.serialize()
projectState = atom.project.serialize({isUnloading: true})
atom.workspace.destroy()
atom.project.destroy()
atom.project = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm.bind(atom)})
atom.project.deserialize(projectState, atom.deserializers)
atom.project.deserialize(projectState)
atom.workspace = new Workspace({
config: atom.config, project: atom.project, packageManager: atom.packages,
grammarRegistry: atom.grammars, deserializerManager: atom.deserializers,

View File

@@ -230,7 +230,7 @@ class AtomEnvironment extends Model
checkPortableHomeWritable()
attachSaveStateListeners: ->
debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval)
debouncedSaveState = _.debounce((=> @saveState({isUnloading: false})), @saveStateDebounceInterval)
@document.addEventListener('mousedown', debouncedSaveState, true)
@document.addEventListener('keydown', debouncedSaveState, true)
@disposables.add new Disposable =>
@@ -684,9 +684,9 @@ class AtomEnvironment extends Model
@openInitialEmptyEditorIfNecessary()
serialize: ->
serialize: (options) ->
version: @constructor.version
project: @project.serialize()
project: @project.serialize(options)
workspace: @workspace.serialize()
packageStates: @packages.serialize()
grammars: {grammarOverridesByPath: @grammars.grammarOverridesByPath}
@@ -831,12 +831,12 @@ class AtomEnvironment extends Model
@blobStore.save()
saveState: ->
saveState: (options) ->
return Promise.resolve() unless @enablePersistence
new Promise (resolve, reject) =>
window.requestIdleCallback =>
state = @serialize()
state = @serialize(options)
savePromise =
if storageKey = @getStateKey(@project?.getPaths())
@stateStore.save(storageKey, state)

View File

@@ -54,7 +54,7 @@ class Project extends Model
Section: Serialization
###
deserialize: (state, deserializerManager) ->
deserialize: (state) ->
state.paths = [state.path] if state.path? # backward compatibility
state.paths = state.paths.filter (directoryPath) -> fs.isDirectorySync(directoryPath)
@@ -66,15 +66,15 @@ class Project extends Model
fs.closeSync(fs.openSync(bufferState.filePath, 'r'))
catch error
return unless error.code is 'ENOENT'
deserializerManager.deserialize(bufferState)
TextBuffer.deserialize(bufferState)
@subscribeToBuffer(buffer) for buffer in @buffers
@setPaths(state.paths)
serialize: ->
serialize: (options) ->
deserializer: 'Project'
paths: @getPaths()
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained())
buffers: _.compact(@buffers.map (buffer) -> buffer.serialize({markerLayers: options.isUnloading is true}) if buffer.isRetained())
###
Section: Event Subscription

View File

@@ -24,16 +24,13 @@ class StateStore {
}
save (key, value) {
// Serialize values using JSON.stringify, as it seems way faster than IndexedDB structured clone.
// (Ref.: https://bugs.chromium.org/p/chromium/issues/detail?id=536620)
let jsonValue = JSON.stringify(value)
return new Promise((resolve, reject) => {
this.dbPromise.then(db => {
if (db == null) resolve()
var request = db.transaction(['states'], 'readwrite')
.objectStore('states')
.put({value: jsonValue, storedAt: new Date().toString(), isJSON: true}, key)
.put({value: value, storedAt: new Date().toString()}, key)
request.onsuccess = resolve
request.onerror = reject
@@ -52,9 +49,8 @@ class StateStore {
request.onsuccess = (event) => {
let result = event.target.result
if (result) {
// TODO: remove this when state will be serialized only via JSON.
resolve(result.isJSON ? JSON.parse(result.value) : result.value)
if (result && !result.isJSON) {
resolve(result.value)
} else {
resolve(null)
}

View File

@@ -143,7 +143,7 @@ class WindowEventHandler
@reloadRequested = false
@atomEnvironment.storeWindowDimensions()
@atomEnvironment.saveState()
@atomEnvironment.saveState({isUnloading: true})
if confirmed
@atomEnvironment.unloadEditorWindow()
else