From 314e3da8bc1ffee72aeb005bde6c9f2f66136a21 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Jan 2013 21:46:44 -0700 Subject: [PATCH] WIP: Destroy nested tab stops when engulfed by a buffer change Has 2 failing specs... There are still some issue with this code's interaction with the undo system. The tab stops will need to be or destroyed when certain changes are undone or redone. --- .atom/snippets/coffee.cson | 4 ++++ src/app/anchor-range.coffee | 13 ++++++++++++ src/app/anchor.coffee | 3 +++ .../snippets/spec/snippets-spec.coffee | 20 +++++++++++++------ .../snippets/src/snippet-expansion.coffee | 6 ++++-- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.atom/snippets/coffee.cson b/.atom/snippets/coffee.cson index f960ce1a5..ff978671c 100644 --- a/.atom/snippets/coffee.cson +++ b/.atom/snippets/coffee.cson @@ -35,6 +35,10 @@ "Point array": prefix: "pt" body: "[$1, $2]" + + "Key-value pair": + prefix: ":" + body: '${1:"${2:key}"}: ${3:value}' "Create Jasmine spy": prefix: "pt" body: 'jasmine.createSpy("${1:description}")$2' diff --git a/src/app/anchor-range.coffee b/src/app/anchor-range.coffee index 7adfa1cf2..1f1ad5151 100644 --- a/src/app/anchor-range.coffee +++ b/src/app/anchor-range.coffee @@ -1,4 +1,7 @@ Range = require 'range' +EventEmitter = require 'event-emitter' +Subscriber = require 'subscriber' +_ = require 'underscore' module.exports = class AnchorRange @@ -6,11 +9,14 @@ class AnchorRange end: null buffer: null editSession: null # optional + destroyed: false constructor: (bufferRange, @buffer, @editSession) -> bufferRange = Range.fromObject(bufferRange) @startAnchor = @buffer.addAnchorAtPosition(bufferRange.start, ignoreChangesStartingOnAnchor: true) @endAnchor = @buffer.addAnchorAtPosition(bufferRange.end) + @subscribe @startAnchor, 'destroyed', => @destroy() + @subscribe @endAnchor, 'destroyed', => @destroy() getBufferRange: -> new Range(@startAnchor.getBufferPosition(), @endAnchor.getBufferPosition()) @@ -22,7 +28,14 @@ class AnchorRange @getBufferRange().containsPoint(bufferPosition) destroy: -> + return if @destroyed + @unsubscribe() @startAnchor.destroy() @endAnchor.destroy() @buffer.removeAnchorRange(this) @editSession?.removeAnchorRange(this) + @destroyed = true + @trigger 'destroyed' + +_.extend(AnchorRange.prototype, EventEmitter) +_.extend(AnchorRange.prototype, Subscriber) diff --git a/src/app/anchor.coffee b/src/app/anchor.coffee index 42932c97c..f0b26b10b 100644 --- a/src/app/anchor.coffee +++ b/src/app/anchor.coffee @@ -10,6 +10,7 @@ class Anchor screenPosition: null ignoreChangesStartingOnAnchor: false strong: false + destroyed: false constructor: (@buffer, options = {}) -> { @editSession, @ignoreChangesStartingOnAnchor, @strong } = options @@ -81,8 +82,10 @@ class Anchor @setScreenPosition(screenPosition, bufferChange: options.bufferChange, clip: false, assignBufferPosition: false, autoscroll: options.autoscroll) destroy: -> + return if @destroyed @buffer.removeAnchor(this) @editSession?.removeAnchor(this) + @destroyed = true @trigger 'destroyed' _.extend(Anchor.prototype, EventEmitter) diff --git a/src/packages/snippets/spec/snippets-spec.coffee b/src/packages/snippets/spec/snippets-spec.coffee index 53598e1fe..38a711489 100644 --- a/src/packages/snippets/spec/snippets-spec.coffee +++ b/src/packages/snippets/spec/snippets-spec.coffee @@ -52,12 +52,9 @@ describe "Snippets extension", -> """ - "multi-line placeholders": + "nested tab stops": prefix: "t5" - body: """ - behold ${1:my multi- - line placeholder}. amazing. - """ + body: '${1:"${2:key}"}: ${3:value}' "caused problems with undo": prefix: "t6" @@ -122,6 +119,17 @@ describe "Snippets extension", -> editor.trigger keydownEvent('tab', target: editor[0]) expect(editor.getSelectedBufferRange()).toEqual [[1, 29], [1, 35]] + describe "when tab stops are nested", -> + it "destroys the inner tab stop if the outer tab stop is modified", -> + buffer.setText('') + editor.insertText 't5' + editor.trigger 'snippets:expand' + expect(buffer.lineForRow(0)).toBe '"key": value' + expect(editor.getSelectedBufferRange()).toEqual [[0, 0], [0, 5]] + editor.insertText("foo") + editor.trigger keydownEvent('tab', target: editor[0]) + expect(editor.getSelectedBufferRange()).toEqual [[0, 5], [0, 10]] + describe "when the cursor is moved beyond the bounds of a tab stop", -> it "terminates the snippet", -> editor.setCursorScreenPosition([2, 0]) @@ -182,7 +190,7 @@ describe "Snippets extension", -> editor.trigger keydownEvent('tab', target: editor[0]) expect(buffer.lineForRow(0)).toBe "first line" - describe "when a snippet expansion is undone and redone", -> + ffdescribe "when a snippet expansion is undone and redone", -> it "recreates the snippet's tab stops", -> editor.insertText ' t6\n' editor.setCursorBufferPosition [0, 6] diff --git a/src/packages/snippets/src/snippet-expansion.coffee b/src/packages/snippets/src/snippet-expansion.coffee index b0e80f83d..dd7a5d11f 100644 --- a/src/packages/snippets/src/snippet-expansion.coffee +++ b/src/packages/snippets/src/snippet-expansion.coffee @@ -25,7 +25,9 @@ class SnippetExpansion placeTabStopAnchorRanges: (startPosition, tabStopRanges) -> @tabStopAnchorRanges = tabStopRanges.map ({start, end}) => - @editSession.addAnchorRange([startPosition.add(start), startPosition.add(end)]) + anchorRange = @editSession.addAnchorRange([startPosition.add(start), startPosition.add(end)]) + anchorRange.on 'destroyed', => _.remove(@tabStopAnchorRanges, anchorRange) + anchorRange @setTabStopIndex(0) indentSubsequentLines: (startRow, snippet) -> @@ -68,7 +70,7 @@ class SnippetExpansion _.intersection(@tabStopAnchorRanges, @editSession.anchorRangesForBufferPosition(bufferPosition)) destroy: -> - anchorRange.destroy() for anchorRange in @tabStopAnchorRanges + anchorRange.destroy() for anchorRange in new Array(@tabStopAnchorRanges...) @editSession.off '.snippet-expansion' @editSession.snippetExpansion = null