diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 17b8dfcdf..b449e99cc 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1968,6 +1968,14 @@ describe "TextEditor", -> expect(editor.lineTextForBufferRow(4)).toBe " current = items.shift();" expect(editor.lineTextForBufferRow(5)).toBe " while(items.length > 0) {" + 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]]]) + editor.moveLineUp() + + expect(editor.getSelectedBufferRanges()).toEqual [[[2, 2], [2, 9]], [[2, 12], [2, 13]]] + expect(editor.lineTextForBufferRow(2)).toBe " var pivot = items.shift(), current, left = [], right = [];" + describe "when one of the selections spans line 0", -> it "doesn't move any lines, since line 0 can't move", -> editor.setSelectedBufferRanges([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 19d501203..c5ce5b189 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -830,34 +830,48 @@ class TextEditor extends Model return @transact => - for selection in selections - selectionRange = selection.getBufferRange() + newSelectionRanges = [] + + while selections.length > 0 + # Find selections spanning a contiguous set of lines + selection = selections.shift() + lastSelectionRange = selection.getBufferRange() + selectionsToMove = [selection] + rangesOfSelectionsToMove = [lastSelectionRange] + + while lastSelectionRange.end.row is selections[0]?.getBufferRange().start.row + selection = selections.shift() + lastSelectionRange = selection.getBufferRange() + selectionsToMove.push(selection) + rangesOfSelectionsToMove.push(lastSelectionRange) + + # Compute the range spanned by all these selections... + linesRangeStart = [selectionsToMove[0].getBufferRange().start.row, 0] + if lastSelectionRange.end.row > lastSelectionRange.start.row and lastSelectionRange.end.column is 0 + # Don't move the last line of a multi-line selection if the selection ends at column 0 + linesRange = new Range(linesRangeStart, lastSelectionRange.end) + else + linesRange = new Range(linesRangeStart, [lastSelectionRange.end.row + 1, 0]) # If selected line range is preceded by a fold, one line above on screen # could be multiple lines in the buffer. - precedingScreenRow = @screenRowForBufferRow(selectionRange.start.row) - 1 + precedingScreenRow = @screenRowForBufferRow(linesRange.start.row) - 1 precedingBufferRow = @bufferRowForScreenRow(precedingScreenRow) - insertDelta = selectionRange.start.row - precedingBufferRow + insertDelta = linesRange.start.row - precedingBufferRow # Any folds in the text that is moved will need to be re-created. rangesToRefold = - @outermostFoldsInBufferRowRange(selectionRange.start.row, selectionRange.end.row).map (fold) -> + @outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) -> fold.getBufferRange().translate([-insertDelta, 0]) # Make sure the inserted text doesn't go into an existing fold if fold = @displayBuffer.largestFoldStartingAtBufferRow(precedingBufferRow) - rangesToRefold.push(fold.getBufferRange().translate([selectionRange.getRowCount(), 0])) + rangesToRefold.push(fold.getBufferRange().translate([linesRange.getRowCount(), 0])) fold.destroy() - # Don't move the last line of a multi-line selection if the selection ends at column 0 - if selectionRange.end.row > selectionRange.start.row and selectionRange.end.column is 0 - linesRange = [[selectionRange.start.row, 0], selectionRange.end] - else - linesRange = [[selectionRange.start.row, 0], [selectionRange.end.row + 1, 0]] - # Delete lines spanned by selection and insert them on the preceding buffer row lines = @buffer.getTextInRange(linesRange) - lines += @buffer.lineEndingForRow(selectionRange.end.row - 1) unless lines[lines.length - 1] is '\n' + lines += @buffer.lineEndingForRow(linesRange.end.row - 1) unless lines[lines.length - 1] is '\n' @buffer.delete(linesRange) @buffer.insert([precedingBufferRow, 0], lines) @@ -865,7 +879,10 @@ class TextEditor extends Model for rangeToRefold in rangesToRefold @displayBuffer.createFold(rangeToRefold.start.row, rangeToRefold.end.row) - selection.setBufferRange(selectionRange.translate([-insertDelta, 0])) + for selection, i in selectionsToMove + newSelectionRanges.push(rangesOfSelectionsToMove[i].translate([-insertDelta, 0])) + + @setSelectedBufferRanges(newSelectionRanges) # Move lines intersecting the most recent selection or muiltiple selections down by one row in screen # coordinates.