diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 1f63d83a8..6e6e1b7b1 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5160,7 +5160,7 @@ describe "TextEditor", -> expect(editor.lineTextForScreenRow(7)).toBe " while(items.length > 0) {" + editor.displayLayer.foldCharacter expect(editor.lineTextForScreenRow(8)).toBe " return sort(left).concat(pivot).concat(sort(right));" - it "duplicates all folded lines for empty selections on folded lines", -> + it "duplicates all folded lines for empty selections on lines containing folds", -> editor.foldBufferRow(4) editor.setCursorBufferPosition([4, 0]) @@ -5191,6 +5191,38 @@ describe "TextEditor", -> """ expect(editor.getSelectedBufferRange()).toEqual [[13, 0], [14, 2]] + it "only duplicates lines containing multiple selections once", -> + editor.setText(""" + aaaaaa + bbbbbb + cccccc + dddddd + """) + editor.setSelectedBufferRanges([ + [[0, 1], [0, 2]], + [[0, 3], [0, 4]], + [[2, 1], [2, 2]], + [[2, 3], [3, 1]], + [[3, 3], [3, 4]], + ]) + editor.duplicateLines() + expect(editor.getText()).toBe(""" + aaaaaa + aaaaaa + bbbbbb + cccccc + dddddd + cccccc + dddddd + """) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 1], [1, 2]], + [[1, 3], [1, 4]], + [[5, 1], [5, 2]], + [[5, 3], [6, 1]], + [[6, 3], [6, 4]], + ]) + describe ".shouldPromptToSave()", -> it "returns true when buffer changed", -> jasmine.unspy(editor, 'shouldPromptToSave') diff --git a/src/text-editor.coffee b/src/text-editor.coffee index cc33c24f4..821322e22 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1272,30 +1272,44 @@ class TextEditor extends Model @setSelectedBufferRanges(translatedRanges) - # Duplicate the most recent cursor's current line. duplicateLines: -> @transact => - for selection in @getSelectionsOrderedByBufferPosition().reverse() - selectedBufferRange = selection.getBufferRange() - if selection.isEmpty() - {start} = selection.getScreenRange() - selection.setScreenRange([[start.row, 0], [start.row + 1, 0]], preserveFolds: true) + selections = @getSelectionsOrderedByBufferPosition() + previousSelectionRanges = [] - [startRow, endRow] = selection.getBufferRowRange() + i = selections.length - 1 + while i >= 0 + j = i + previousSelectionRanges[i] = selections[i].getBufferRange() + if selections[i].isEmpty() + {start} = selections[i].getScreenRange() + selections[i].setScreenRange([[start.row, 0], [start.row + 1, 0]], preserveFolds: true) + [startRow, endRow] = selections[i].getBufferRowRange() endRow++ + while i > 0 + [previousSelectionStartRow, previousSelectionEndRow] = selections[i - 1].getBufferRowRange() + if previousSelectionEndRow is startRow + startRow = previousSelectionStartRow + previousSelectionRanges[i - 1] = selections[i - 1].getBufferRange() + i-- + else + break intersectingFolds = @displayLayer.foldsIntersectingBufferRange([[startRow, 0], [endRow, 0]]) - rangeToDuplicate = [[startRow, 0], [endRow, 0]] - textToDuplicate = @getTextInBufferRange(rangeToDuplicate) + textToDuplicate = @getTextInBufferRange([[startRow, 0], [endRow, 0]]) textToDuplicate = '\n' + textToDuplicate if endRow > @getLastBufferRow() @buffer.insert([endRow, 0], textToDuplicate) - delta = endRow - startRow - selection.setBufferRange(selectedBufferRange.translate([delta, 0])) + insertedRowCount = endRow - startRow + + for k in [i..j] by 1 + selections[k].setBufferRange(previousSelectionRanges[k].translate([insertedRowCount, 0])) + for fold in intersectingFolds foldRange = @displayLayer.bufferRangeForFold(fold) - @displayLayer.foldBufferRange(foldRange.translate([delta, 0])) - return + @displayLayer.foldBufferRange(foldRange.translate([insertedRowCount, 0])) + + i-- replaceSelectedText: (options={}, fn) -> {selectWordIfEmpty} = options