From 0782f0f4d0d3b07d439e92795450d685fb8065bb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 19 Sep 2017 14:17:04 -0400 Subject: [PATCH] "Retire" buffer IDs when the buffer can't be deserialized --- spec/text-editor-spec.coffee | 9 +++++++++ src/project.coffee | 32 ++++++++++++-------------------- src/text-editor.coffee | 5 ++++- src/tokenized-buffer.coffee | 8 ++++++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 47b85bf1f..cb70d030c 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -76,6 +76,15 @@ describe "TextEditor", -> expect(editor2.displayLayer.tabLength).toBe(editor2.getTabLength()) expect(editor2.displayLayer.softWrapColumn).toBe(editor2.getSoftWrapColumn()) + it "ignores buffers with retired IDs", -> + editor2 = TextEditor.deserialize(editor.serialize(), { + assert: atom.assert, + textEditors: atom.textEditors, + project: {bufferForIdSync: -> null} + }) + + expect(editor2).toBeNull() + describe "when the editor is constructed with the largeFileMode option set to true", -> it "loads the editor but doesn't tokenize", -> editor = null diff --git a/src/project.coffee b/src/project.coffee index 486d003e3..7e5cf975e 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -30,6 +30,8 @@ class Project extends Model @repositoryProviders = [new GitRepositoryProvider(this, config)] @loadPromisesByPath = {} @watcherPromisesByPath = {} + @retiredBufferIDs = new Set() + @retiredBufferPaths = new Set() @consumeServices(packageManager) destroyed: -> @@ -58,29 +60,17 @@ class Project extends Model ### deserialize: (state) -> - checkNotDirectory = (filePath) -> - new Promise (resolve, reject) -> - fs.isDirectory filePath, (isDir) -> - if isDir then reject() else resolve() + @retiredBufferIDs = new Set() + @retiredBufferPaths = new Set() - checkAccess = (filePath) -> - new Promise (resolve, reject) -> - fs.open filePath, 'r', (err, fd) -> - return reject() if err? - fs.close fd, () -> resolve() - - handleBufferState = (bufferState) -> + handleBufferState = (bufferState) => bufferState.shouldDestroyOnFileDelete ?= -> atom.config.get('core.closeDeletedFileTabs') + bufferState.mustExist = true - promise = Promise.resolve() - if bufferState.filePath? - promise = promise.then () -> Promise.all([ - checkNotDirectory(bufferState.filePath), - checkAccess(bufferState.filePath) - ]) - promise = promise.then () -> TextBuffer.deserialize(bufferState) - promise = promise.catch (err) -> null - promise + TextBuffer.deserialize(bufferState).catch (err) => + @retiredBufferIDs.add(bufferState.id) + @retiredBufferPaths.add(bufferState.filePath) + null bufferPromises = (handleBufferState(bufferState) for bufferState in state.buffers) @@ -465,11 +455,13 @@ class Project extends Model # Only to be used in specs bufferForPathSync: (filePath) -> absoluteFilePath = @resolvePath(filePath) + return null if @retiredBufferPaths.has absoluteFilePath existingBuffer = @findBufferForPath(absoluteFilePath) if filePath existingBuffer ? @buildBufferSync(absoluteFilePath) # Only to be used when deserializing bufferForIdSync: (id) -> + return null if @retiredBufferIDs.has id existingBuffer = @findBufferForId(id) if id existingBuffer ? @buildBufferSync() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index b97e63957..a84f6f631 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -128,7 +128,10 @@ class TextEditor extends Model state.tokenizedBuffer = state.displayBuffer.tokenizedBuffer try - state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer, atomEnvironment) + tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer, atomEnvironment) + return null unless tokenizedBuffer? + + state.tokenizedBuffer = tokenizedBuffer state.tabLength = state.tokenizedBuffer.getTabLength() catch error if error.syscall is 'read' diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 8fca6c06b..e4d954a59 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -23,11 +23,15 @@ class TokenizedBuffer extends Model changeCount: 0 @deserialize: (state, atomEnvironment) -> + buffer = null if state.bufferId - state.buffer = atomEnvironment.project.bufferForIdSync(state.bufferId) + buffer = atomEnvironment.project.bufferForIdSync(state.bufferId) else # TODO: remove this fallback after everyone transitions to the latest version. - state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) + buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) + return null unless buffer? + + state.buffer = buffer state.assert = atomEnvironment.assert new this(state)