From dacd08badfa45f40a5cd6b0f38466a57339d004d Mon Sep 17 00:00:00 2001 From: abe33 Date: Tue, 3 Nov 2015 00:48:22 +0100 Subject: [PATCH] :bug: Fix moving multiple selection with folds creates new folds --- spec/fixtures/sample-with-many-folds.js | 12 +++++ spec/text-editor-spec.coffee | 70 ++++++++++++++++++++++++- src/text-editor.coffee | 31 +++++++---- 3 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 spec/fixtures/sample-with-many-folds.js diff --git a/spec/fixtures/sample-with-many-folds.js b/spec/fixtures/sample-with-many-folds.js new file mode 100644 index 000000000..a3c5b7acc --- /dev/null +++ b/spec/fixtures/sample-with-many-folds.js @@ -0,0 +1,12 @@ +1; +2; +function f3() { + return 4; +}; +6; +7; +function f8() { + return 9; +}; +11; +12; diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 668842c67..bcf4fe7b8 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2077,6 +2077,39 @@ describe "TextEditor", -> expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() + describe 'when there are many folds', -> + beforeEach -> + waitsForPromise -> + atom.workspace.open('sample-with-many-folds.js', autoIndent: false).then (o) -> editor = o + + describe 'and many selections intersects folded rows', -> + it 'moves and preserves all the folds', -> + editor.createFold(2, 4) + editor.createFold(7, 9) + + editor.setSelectedBufferRanges([ + [[1, 0], [5, 4]], + [[7, 0], [7, 4]] + ], preserveFolds: true) + + editor.moveLineUp() + + expect(editor.lineTextForBufferRow(1)).toEqual "function f3() {" + expect(editor.lineTextForBufferRow(4)).toEqual "6;" + expect(editor.lineTextForBufferRow(5)).toEqual "1;" + expect(editor.lineTextForBufferRow(6)).toEqual "function f8() {" + expect(editor.lineTextForBufferRow(9)).toEqual "7;" + + expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(2)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(4)).toBeFalsy() + + expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() + describe "when some of the selections span the same lines", -> it "moves lines that contain multiple selections correctly", -> editor.setSelectedBufferRanges([[[3, 2], [3, 9]], [[3, 12], [3, 13]]]) @@ -2103,7 +2136,7 @@ describe "TextEditor", -> expect(editor.getSelectedBufferRanges()).toEqual [[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[13, 0], [13, 0]]] - describe ".moveLineDown", -> + fdescribe ".moveLineDown", -> describe "when there is a single selection", -> describe "when the selection spans a single line", -> describe "when there is no fold in the following row", -> @@ -2295,6 +2328,41 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(5)).toBe " current < pivot ? left.push(current) : right.push(current);" expect(editor.lineTextForBufferRow(6)).toBe " current = items.shift();" + describe 'when there are many folds', -> + beforeEach -> + waitsForPromise -> + atom.workspace.open('sample-with-many-folds.js', autoIndent: false).then (o) -> editor = o + + describe 'and many selections intersects folded rows', -> + it 'moves and preserves all the folds', -> + editor.createFold(2, 4) + editor.createFold(7, 9) + + editor.setSelectedBufferRanges([ + [[2, 0], [2, 4]], + [[6, 0], [10, 4]] + ], preserveFolds: true) + + editor.moveLineDown() + + expect(editor.lineTextForBufferRow(2)).toEqual "6;" + expect(editor.lineTextForBufferRow(3)).toEqual "function f3() {" + expect(editor.lineTextForBufferRow(6)).toEqual "12;" + expect(editor.lineTextForBufferRow(7)).toEqual "7;" + expect(editor.lineTextForBufferRow(8)).toEqual "function f8() {" + expect(editor.lineTextForBufferRow(11)).toEqual "11;" + + expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() + expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(6)).toBeFalsy() + expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() + expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(9)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(10)).toBeTruthy() + expect(editor.isFoldedAtBufferRow(11)).toBeFalsy() + describe "when there is a fold below one of the selected row", -> it "moves all lines spanned by a selection to the following row, preserving the fold", -> editor.createFold(4, 7) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 151ca4528..d64bcb47c 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -900,13 +900,19 @@ class TextEditor extends Model linesRange = new Range(linesRangeStart, [selection.end.row + 1, 0]) # If there's a fold containing either the starting row or the end row - # of the selection then the whole fold needs to be moved. - if fold = @displayBuffer.largestFoldContainingBufferRow(selection.start.row) - newEndRow = fold.getBufferRange().end.row + 1 - linesRange.end.row = newEndRow if newEndRow > linesRange.end.row - else if fold = @displayBuffer.largestFoldContainingBufferRow(selection.end.row) - newEndRow = fold.getBufferRange().end.row + 1 + # of the selection then the whole fold needs to be moved and restored. + # The initial fold range is stored and will be translated once the + # insert delta is know. + selectionFoldRanges = [] + foldAtSelectionStart = + @displayBuffer.largestFoldContainingBufferRow(selection.start.row) + foldAtSelectionEnd = + @displayBuffer.largestFoldContainingBufferRow(selection.end.row) + if fold = foldAtSelectionStart ? foldAtSelectionEnd + selectionFoldRanges.push range = fold.getBufferRange() + newEndRow = range.end.row + 1 linesRange.end.row = newEndRow if newEndRow > linesRange.end.row + fold.destroy() # If selected line range is preceded by a fold, one line above on screen # could be multiple lines in the buffer. @@ -915,9 +921,13 @@ class TextEditor extends Model insertDelta = linesRange.start.row - precedingBufferRow # Any folds in the text that is moved will need to be re-created. - rangesToRefold = + # It includes the folds that were intersecting with the selection. + rangesToRefold = selectionFoldRanges.concat( @outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) -> - fold.getBufferRange().translate([-insertDelta, 0]) + range = fold.getBufferRange() + fold.destroy() + range + ).map (range) -> range.translate([-insertDelta, 0]) # Make sure the inserted text doesn't go into an existing fold if fold = @displayBuffer.largestFoldStartingAtBufferRow(precedingBufferRow) @@ -996,7 +1006,10 @@ class TextEditor extends Model # Any folds in the text that is moved will need to be re-created. # It includes the folds that were intersecting with the selection. rangesToRefold = selectionFoldRanges.concat( - @outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) -> fold.getBufferRange() + @outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) -> + range = fold.getBufferRange() + fold.destroy() + range ).map (range) -> range.translate([insertDelta, 0]) # Make sure the inserted text doesn't go into an existing fold