From d0d187f36aa6452f00b6370fd4e1e5ef528cfce9 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 30 Dec 2016 16:43:44 -0800 Subject: [PATCH 01/10] Reduce the impact of leaking Editor, Selection, & Cursor objects Signed-off-by: Nathan Sobo --- src/cursor.coffee | 1 + src/selection.coffee | 2 ++ src/text-editor.coffee | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/cursor.coffee b/src/cursor.coffee index 85573f10e..05242f90a 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -26,6 +26,7 @@ class Cursor extends Model destroy: -> @marker.destroy() + @marker = null ### Section: Event Subscription diff --git a/src/selection.coffee b/src/selection.coffee index 8aa86157e..18297e5f7 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -26,6 +26,8 @@ class Selection extends Model destroy: -> @marker.destroy() + @marker = null + @decoration = null isLastSelection: -> this is @editor.getLastSelection() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 3ee268b95..f3fb7abdb 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -408,16 +408,27 @@ class TextEditor extends Model @emitter.emit 'did-change', {} destroyed: -> + @emitter.emit 'did-destroy' + @emitter = null @disposables.dispose() @displayLayer.destroy() - @disposables.dispose() + @displayLayer = null + @defaultMarkerLayer = null @tokenizedBuffer.destroy() + @tokenizedBuffer = null selection.destroy() for selection in @selections.slice() - @selectionsMarkerLayer.destroy() + @selections = null + @cursors = null + @selectionsMarkerLayer = null @buffer.release() + @buffer = null + @decorationManager = null @languageMode.destroy() + @languageMode = null @gutterContainer.destroy() - @emitter.emit 'did-destroy' + @gutterContainer = null + @editorElement = null + @presenter = null ### Section: Event Subscription From 11b19b8c0ff6e769a29ab479d9f8f6b51f91a0ac Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 30 Dec 2016 16:44:49 -0800 Subject: [PATCH 02/10] :arrow_up: text-buffer (prerelease) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5acc04465..3803d7abe 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "sinon": "1.17.4", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "10.2.1", + "text-buffer": "10.2.2-0", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", From f4371efb7442cf3c680cf42230a963325ca3fba8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 2 Jan 2017 11:31:43 -0800 Subject: [PATCH 03/10] Fix usages of destroyed buffers in specs --- spec/text-editor-spec.coffee | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c2f66a5e2..2432a66b0 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -4325,15 +4325,10 @@ describe "TextEditor", -> expect(editor.getLastSelection().isEmpty()).toBeTruthy() it "does not explode if the current language mode has no comment regex", -> - editor.destroy() - - waitsForPromise -> - atom.workspace.open(null, autoIndent: false).then (o) -> editor = o - - runs -> - editor.setSelectedBufferRange([[4, 5], [4, 5]]) - editor.toggleLineCommentsInSelection() - expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {" + editor = new TextEditor(buffer: new TextBuffer(text: 'hello')) + editor.setSelectedBufferRange([[0, 0], [0, 5]]) + editor.toggleLineCommentsInSelection() + expect(editor.lineTextForBufferRow(0)).toBe "hello" it "does nothing for empty lines and null grammar", -> runs -> @@ -5056,11 +5051,13 @@ describe "TextEditor", -> describe ".destroy()", -> it "destroys marker layers associated with the text editor", -> + buffer.retain() selectionsMarkerLayerId = editor.selectionsMarkerLayer.id foldsMarkerLayerId = editor.displayLayer.foldsMarkerLayer.id editor.destroy() expect(buffer.getMarkerLayer(selectionsMarkerLayerId)).toBeUndefined() expect(buffer.getMarkerLayer(foldsMarkerLayerId)).toBeUndefined() + buffer.release() it "notifies ::onDidDestroy observers when the editor is destroyed", -> destroyObserverCalled = false From a7f390d2b6f0e8591f8c09e217fae6cb83493d20 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 2 Jan 2017 11:35:47 -0800 Subject: [PATCH 04/10] :arrow_up: text-buffer (prerelease) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3803d7abe..00659e91c 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "sinon": "1.17.4", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "10.2.2-0", + "text-buffer": "10.2.2-1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", From 79e68b462d2f29fba0b7f2907d559612babfa345 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 2 Jan 2017 11:55:41 -0800 Subject: [PATCH 05/10] Avoid using torn-down properties in specs --- spec/selection-spec.coffee | 3 ++- spec/text-editor-presenter-spec.coffee | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/selection-spec.coffee b/spec/selection-spec.coffee index 1b21d7411..cb070310a 100644 --- a/spec/selection-spec.coffee +++ b/spec/selection-spec.coffee @@ -81,8 +81,9 @@ describe "Selection", -> describe "when the selection is destroyed", -> it "destroys its marker", -> selection.setBufferRange([[2, 0], [2, 10]]) + marker = selection.marker selection.destroy() - expect(selection.marker.isDestroyed()).toBeTruthy() + expect(marker.isDestroyed()).toBeTruthy() describe ".insertText(text, options)", -> it "allows pasting white space only lines when autoIndent is enabled", -> diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 12aba8eee..498b71393 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2181,7 +2181,7 @@ describe "TextEditorPresenter", -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false) waitsForStateToUpdate presenter - destroyedSelection = null + [destroyedSelection, destroyedDecoration] = [] runs -> expectValues stateForSelectionInTile(presenter, 2, 0), { regions: [{top: 10, left: 4 * 10, width: 4 * 10, height: 10}] @@ -2189,10 +2189,11 @@ describe "TextEditorPresenter", -> # destroying destroyedSelection = editor.getSelections()[2] + destroyedDecoration = destroyedSelection.decoration waitsForStateToUpdate presenter, -> destroyedSelection.destroy() runs -> - expectUndefinedStateForHighlight(presenter, destroyedSelection.decoration) + expectUndefinedStateForHighlight(presenter, destroyedDecoration) it "updates when highlight decorations' properties are updated", -> marker = editor.markBufferPosition([2, 2]) From 6f13159549f07a47354fdaae750f5fcf35a989ec Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 3 Jan 2017 14:00:50 -0800 Subject: [PATCH 06/10] Don't throw exceptions when using editor APIs after destroying the editor Signed-off-by: Nathan Sobo --- spec/text-editor-spec.coffee | 6 ++++++ src/cursor.coffee | 1 - src/selection.coffee | 2 -- src/text-editor.coffee | 12 +----------- src/tokenized-buffer.coffee | 2 ++ 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 2432a66b0..5e5c0232e 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5066,6 +5066,12 @@ describe "TextEditor", -> editor.destroy() expect(destroyObserverCalled).toBe true + it "does not blow up when query methods are called afterward", -> + editor.destroy() + editor.getGrammar() + editor.getLastCursor() + editor.lineTextForBufferRow(0) + describe ".joinLines()", -> describe "when no text is selected", -> describe "when the line below isn't empty", -> diff --git a/src/cursor.coffee b/src/cursor.coffee index 05242f90a..85573f10e 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -26,7 +26,6 @@ class Cursor extends Model destroy: -> @marker.destroy() - @marker = null ### Section: Event Subscription diff --git a/src/selection.coffee b/src/selection.coffee index 18297e5f7..8aa86157e 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -26,8 +26,6 @@ class Selection extends Model destroy: -> @marker.destroy() - @marker = null - @decoration = null isLastSelection: -> this is @editor.getLastSelection() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f3fb7abdb..f3a11ba3d 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -409,24 +409,14 @@ class TextEditor extends Model destroyed: -> @emitter.emit 'did-destroy' - @emitter = null + @emitter.clear() @disposables.dispose() @displayLayer.destroy() - @displayLayer = null - @defaultMarkerLayer = null @tokenizedBuffer.destroy() - @tokenizedBuffer = null selection.destroy() for selection in @selections.slice() - @selections = null - @cursors = null - @selectionsMarkerLayer = null @buffer.release() - @buffer = null - @decorationManager = null @languageMode.destroy() - @languageMode = null @gutterContainer.destroy() - @gutterContainer = null @editorElement = null @presenter = null diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 8f6c1cb64..234f82be9 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -41,6 +41,7 @@ class TokenizedBuffer extends Model destroyed: -> @disposables.dispose() + @tokenizedLines.length = 0 buildIterator: -> new TokenizedBufferIterator(this) @@ -94,6 +95,7 @@ class TokenizedBuffer extends Model false retokenizeLines: -> + return unless @alive @fullyTokenized = false @tokenizedLines = new Array(@buffer.getLineCount()) @invalidRows = [] From 8eb8285e58eda2907eae81f69d1ae39202305c67 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 3 Jan 2017 14:00:57 -0800 Subject: [PATCH 07/10] :arrow_up: text-buffer (prerelease) Signed-off-by: Nathan Sobo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 00659e91c..b864e38a4 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "sinon": "1.17.4", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "10.2.2-1", + "text-buffer": "10.2.2-2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1", From 126f5380ba0fde10d229436dca6bb867ce78c110 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 3 Jan 2017 15:18:01 -0800 Subject: [PATCH 08/10] Emit editor destroyed event after releasing the editor's buffer --- spec/text-editor-spec.coffee | 11 +++++++++++ src/text-editor.coffee | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 5e5c0232e..1f63d83a8 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5072,6 +5072,17 @@ describe "TextEditor", -> editor.getLastCursor() editor.lineTextForBufferRow(0) + it "emits the destroy event after destroying the editor's buffer", -> + events = [] + editor.getBuffer().onDidDestroy -> + expect(editor.isDestroyed()).toBe(true) + events.push('buffer-destroyed') + editor.onDidDestroy -> + expect(buffer.isDestroyed()).toBe(true) + events.push('editor-destroyed') + editor.destroy() + expect(events).toEqual(['buffer-destroyed', 'editor-destroyed']) + describe ".joinLines()", -> describe "when no text is selected", -> describe "when the line below isn't empty", -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f3a11ba3d..cc33c24f4 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -408,8 +408,6 @@ class TextEditor extends Model @emitter.emit 'did-change', {} destroyed: -> - @emitter.emit 'did-destroy' - @emitter.clear() @disposables.dispose() @displayLayer.destroy() @tokenizedBuffer.destroy() @@ -417,6 +415,8 @@ class TextEditor extends Model @buffer.release() @languageMode.destroy() @gutterContainer.destroy() + @emitter.emit 'did-destroy' + @emitter.clear() @editorElement = null @presenter = null From 8277f69d45adaf49e5190485bd21b419e5abc627 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 3 Jan 2017 15:29:58 -0800 Subject: [PATCH 09/10] :arrow_up: find-and-replace, spell-check, whitespace --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b864e38a4..990d59bfa 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.22.0", "exception-reporting": "0.40.1", - "find-and-replace": "0.205.0", + "find-and-replace": "0.205.1", "fuzzy-finder": "1.4.1", "git-diff": "1.2.0", "go-to-line": "0.31.2", @@ -118,7 +118,7 @@ "package-generator": "1.0.2", "settings-view": "0.244.0", "snippets": "1.0.4", - "spell-check": "0.70.0", + "spell-check": "0.70.2", "status-bar": "1.7.0", "styleguide": "0.48.0", "symbols-view": "0.114.0", @@ -127,7 +127,7 @@ "tree-view": "0.211.1", "update-package-dependencies": "0.10.0", "welcome": "0.35.2", - "whitespace": "0.36.0", + "whitespace": "0.36.1", "wrap-guide": "0.39.0", "language-c": "0.54.0", "language-clojure": "0.22.1", From 7082e291c9cf3b0e9596935e2eb91b3e4c0cd597 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 3 Jan 2017 16:07:23 -0800 Subject: [PATCH 10/10] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ede02043..dfe5aa323 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "sinon": "1.17.4", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "10.2.2-2", + "text-buffer": "10.2.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "winreg": "^1.2.1",