diff --git a/spec/atom/editor-spec.coffee b/spec/atom/editor-spec.coffee index f69abb81b..90e0cf6c3 100644 --- a/spec/atom/editor-spec.coffee +++ b/spec/atom/editor-spec.coffee @@ -757,11 +757,13 @@ describe "Editor", -> describe "folding", -> describe "when a fold-selection event is triggered", -> - it "folds the selected text and moves the cursor to just after the placeholder", -> + it "folds the selected text and moves the cursor to just after the placeholder, then treats the placeholder as a single character", -> editor.selection.setBufferRange(new Range([4, 29], [7, 4])) - editor.trigger 'fold-selection' + expect(editor.lines.find('.line:eq(4)').find('.fold-placeholder')).toExist() + expect(editor.lines.find('.line:eq(5)').text()).toBe ' return sort(left).concat(pivot).concat(sort(right));' + expect(editor.selection.isEmpty()).toBeTruthy() expect(editor.getCursorScreenPosition()).toEqual [4, 32] @@ -777,4 +779,14 @@ describe "Editor", -> editor.moveCursorRight() expect(editor.getCursorScreenPosition()).toEqual [4, 32] + describe "when a fold placeholder is clicked", -> + it "removes the associated fold", -> + editor.selection.setBufferRange(new Range([4, 29], [7, 4])) + editor.trigger 'fold-selection' + + editor.find('.fold-placeholder .ellipsis').mousedown() + + expect(editor.find('.fold-placeholder')).not.toExist() + expect(editor.lines.find('.line:eq(5)').text()).toBe ' current = items.shift();' + diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index d498a5b03..cbdaecddf 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -92,6 +92,10 @@ class Editor extends View @hiddenInput.focus() false + @on 'mousedown', '.fold-placeholder', (e) => + @lineFolder.destroyFoldById($(e.currentTarget).attr('foldId')) + false + @on 'mousedown', (e) => clickCount = e.originalEvent.detail @@ -130,7 +134,7 @@ class Editor extends View if tokens.length for token in tokens if token.type is 'fold-placeholder' - @span ' ', class: 'fold-placeholder', style: "width: #{3 * charWidth}px; height: #{charHeight * .85 }px;", => + @span ' ', class: 'fold-placeholder', style: "width: #{3 * charWidth}px; height: #{charHeight * .85 }px;", 'foldId': token.fold.id, => @div class: "ellipsis", => @raw "…" else @span { class: token.type.replace('.', ' ') }, token.value diff --git a/src/atom/line-folder.coffee b/src/atom/line-folder.coffee index 719e4b24b..9e26b600b 100644 --- a/src/atom/line-folder.coffee +++ b/src/atom/line-folder.coffee @@ -7,11 +7,14 @@ EventEmitter = require 'event-emitter' module.exports = class LineFolder + activeFolds: null + foldsById: null lineMap: null lastHighlighterChangeEvent: null constructor: (@highlighter) -> @activeFolds = {} + @foldsById = {} @buildLineMap() @highlighter.buffer.on 'change', (e) => @handleBufferChange(e) @highlighter.on 'change', (e) => @lastHighlighterChangeEvent = e @@ -57,13 +60,18 @@ class LineFolder @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange @trigger 'unfold', fold.getRange() + destroyFoldById: (foldId) -> + @foldsById[foldId]?.destroy() + registerFold: (bufferRow, fold) -> @activeFolds[bufferRow] ?= [] @activeFolds[bufferRow].push(fold) + @foldsById[fold.id] = fold unregisterFold: (bufferRow, fold) -> folds = @activeFolds[bufferRow] folds.splice(folds.indexOf(fold), 1) + delete @foldsById[fold.id] handleBufferChange: (e) -> for row, folds of @activeFolds @@ -102,7 +110,7 @@ class LineFolder screenLine buildFoldPlaceholder: (fold) -> - new ScreenLineFragment([{value: '...', type: 'fold-placeholder'}], '...', [0, 3], fold.getRange().toDelta(), isAtomic: true) + new ScreenLineFragment([{value: '...', type: 'fold-placeholder', fold}], '...', [0, 3], fold.getRange().toDelta(), isAtomic: true) foldsForBufferRow: (bufferRow) -> @activeFolds[bufferRow] or [] @@ -150,7 +158,10 @@ class LineFolder _.extend LineFolder.prototype, EventEmitter class Fold + @idCounter: 1 + constructor: (@lineFolder, {@start, @end}) -> + @id = @constructor.idCounter++ destroy: -> @lineFolder.destroyFold(this)