Merge pull request #1534 from atom/ks-move-lines-around-folds

Handle moving lines around folds
This commit is contained in:
Kevin Sawicki
2014-02-11 16:06:23 -08:00
2 changed files with 147 additions and 18 deletions

View File

@@ -2532,6 +2532,52 @@ describe "EditorView", ->
editorView.trigger 'editor:move-line-up'
expect(editor.getCursorBufferPosition()).toEqual [0,2]
describe "when the line above is folded", ->
it "moves the line around the fold", ->
editor.foldBufferRow(1)
editor.setCursorBufferPosition([10, 0])
editorView.trigger 'editor:move-line-up'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
expect(buffer.lineForRow(1)).toBe ''
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
expect(editor.isFoldedAtBufferRow(1)).toBe false
expect(editor.isFoldedAtBufferRow(2)).toBe true
describe "when the line being moved is folded", ->
it "moves the fold around the fold above it", ->
editor.setCursorBufferPosition([0, 0])
editor.insertText """
var a = function() {
b = 3;
};
"""
editor.foldBufferRow(0)
editor.foldBufferRow(3)
editor.setCursorBufferPosition([3, 0])
editorView.trigger 'editor:move-line-up'
expect(editor.getCursorBufferPosition()).toEqual [0, 0]
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
editor.logScreenLines()
expect(editor.isFoldedAtBufferRow(0)).toBe true
expect(editor.isFoldedAtBufferRow(13)).toBe true
describe "when the line above is empty and the line above that is folded", ->
it "moves the line to the empty line", ->
editor.foldBufferRow(2)
editor.setCursorBufferPosition([11, 0])
editorView.trigger 'editor:move-line-up'
expect(editor.getCursorBufferPosition()).toEqual [10, 0]
expect(buffer.lineForRow(9)).toBe ' };'
expect(buffer.lineForRow(10)).toBe ' return sort(Array.apply(this, arguments));'
expect(buffer.lineForRow(11)).toBe ''
expect(editor.isFoldedAtBufferRow(2)).toBe true
expect(editor.isFoldedAtBufferRow(10)).toBe false
describe "where there is a selection", ->
describe "when the selection falls inside the line", ->
it "maintains the selection", ->
@@ -2631,6 +2677,54 @@ describe "EditorView", ->
editorView.trigger 'editor:move-line-down'
expect(editor.getCursorBufferPosition()).toEqual [1, 2]
describe "when the line below is folded", ->
it "moves the line around the fold", ->
editor.setCursorBufferPosition([0, 0])
editor.foldBufferRow(1)
editorView.trigger 'editor:move-line-down'
expect(editor.getCursorBufferPosition()).toEqual [9, 0]
expect(buffer.lineForRow(0)).toBe ' var sort = function(items) {'
expect(buffer.lineForRow(9)).toBe 'var quicksort = function () {'
expect(editor.isFoldedAtBufferRow(0)).toBe true
expect(editor.isFoldedAtBufferRow(9)).toBe false
describe "when the line being moved is folded", ->
it "moves the fold around the fold below it", ->
editor.setCursorBufferPosition([0, 0])
editor.insertText """
var a = function() {
b = 3;
};
"""
editor.foldBufferRow(0)
editor.foldBufferRow(3)
editor.setCursorBufferPosition([0, 0])
editorView.trigger 'editor:move-line-down'
expect(editor.getCursorBufferPosition()).toEqual [13, 0]
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
expect(buffer.lineForRow(13)).toBe 'var a = function() {'
expect(editor.isFoldedAtBufferRow(0)).toBe true
expect(editor.isFoldedAtBufferRow(13)).toBe true
describe "when the line below is empty and the line below that is folded", ->
it "moves the line to the empty line", ->
editor.setCursorBufferPosition([0, Infinity])
editor.insertText('\n')
editor.setCursorBufferPosition([0, 0])
editor.foldBufferRow(2)
editorView.trigger 'editor:move-line-down'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
expect(buffer.lineForRow(0)).toBe ''
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
expect(editor.isFoldedAtBufferRow(0)).toBe false
expect(editor.isFoldedAtBufferRow(1)).toBe false
expect(editor.isFoldedAtBufferRow(2)).toBe true
describe "when the cursor is on the last line", ->
it "does not move the line", ->
editor.moveCursorToBottom()

View File

@@ -621,7 +621,7 @@ class Editor extends Model
largestFoldStartingAtScreenRow: (screenRow) ->
@displayBuffer.largestFoldStartingAtScreenRow(screenRow)
# Public: Moves the selected line up one row.
# Public: Moves the selected lines up one screen row.
moveLineUp: ->
selection = @getSelectedBufferRange()
return if selection.start.row is 0
@@ -633,29 +633,47 @@ class Editor extends Model
rows = [selection.start.row..selection.end.row]
if selection.start.row isnt selection.end.row and selection.end.column is 0
rows.pop() unless @isFoldedAtBufferRow(selection.end.row)
# Move line around the fold that is directly above the selection
precedingScreenRow = @screenPositionForBufferPosition([selection.start.row]).translate([-1])
precedingBufferRow = @bufferPositionForScreenPosition(precedingScreenRow).row
if fold = @largestFoldContainingBufferRow(precedingBufferRow)
insertDelta = fold.getBufferRange().getRowCount()
else
insertDelta = 1
for row in rows
screenRow = @screenPositionForBufferPosition([row]).row
if @isFoldedAtScreenRow(screenRow)
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
bufferRange = fold.getBufferRange()
startRow = bufferRange.start.row
endRow = bufferRange.end.row - 1
foldedRows.push(endRow - 1)
endRow = bufferRange.end.row
foldedRows.push(startRow - insertDelta)
else
startRow = row
endRow = row
insertPosition = Point.fromObject([startRow - insertDelta])
endPosition = Point.min([endRow + 1], @buffer.getEofPosition())
lines = @buffer.getTextInRange([[startRow], endPosition])
if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row)
lines = "#{lines}\n"
@buffer.deleteRows(startRow, endRow)
@buffer.insert([startRow - 1], lines)
@foldBufferRow(foldedRow) for foldedRow in foldedRows
# Make sure the inserted text doesn't go into an existing fold
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
@destroyFoldsContainingBufferRow(insertPosition.row)
foldedRows.push(insertPosition.row + endRow - startRow + fold.getBufferRange().getRowCount())
@setSelectedBufferRange(selection.translate([-1]), preserveFolds: true)
@buffer.insert(insertPosition, lines)
# Public: Moves the selected line down one row.
# Restore folds that existed before the lines were moved
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
@foldBufferRow(foldedRow)
@setSelectedBufferRange(selection.translate([-insertDelta]), preserveFolds: true)
# Public: Moves the selected lines down one screen row.
moveLineDown: ->
selection = @getSelectedBufferRange()
lastRow = @buffer.getLastRow()
@@ -667,13 +685,21 @@ class Editor extends Model
rows = [selection.end.row..selection.start.row]
if selection.start.row isnt selection.end.row and selection.end.column is 0
rows.shift() unless @isFoldedAtBufferRow(selection.end.row)
# Move line around the fold that is directly below the selection
followingScreenRow = @screenPositionForBufferPosition([selection.end.row]).translate([1])
followingBufferRow = @bufferPositionForScreenPosition(followingScreenRow).row
if fold = @largestFoldContainingBufferRow(followingBufferRow)
insertDelta = fold.getBufferRange().getRowCount()
else
insertDelta = 1
for row in rows
screenRow = @screenPositionForBufferPosition([row]).row
if @isFoldedAtScreenRow(screenRow)
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
bufferRange = fold.getBufferRange()
startRow = bufferRange.start.row
endRow = bufferRange.end.row - 1
foldedRows.push(endRow + 1)
endRow = bufferRange.end.row
foldedRows.push(endRow + insertDelta)
else
startRow = row
endRow = row
@@ -684,14 +710,23 @@ class Editor extends Model
endPosition = [endRow + 1]
lines = @buffer.getTextInRange([[startRow], endPosition])
@buffer.deleteRows(startRow, endRow)
insertPosition = Point.min([startRow + 1], @buffer.getEofPosition())
insertPosition = Point.min([startRow + insertDelta], @buffer.getEofPosition())
if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0
lines = "\n#{lines}"
# Make sure the inserted text doesn't go into an existing fold
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
@destroyFoldsContainingBufferRow(insertPosition.row)
foldedRows.push(insertPosition.row + fold.getBufferRange().getRowCount())
@buffer.insert(insertPosition, lines)
@foldBufferRow(foldedRow) for foldedRow in foldedRows
# Restore folds that existed before the lines were moved
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
@foldBufferRow(foldedRow)
@setSelectedBufferRange(selection.translate([1]), preserveFolds: true)
@setSelectedBufferRange(selection.translate([insertDelta]), preserveFolds: true)
# Public: Duplicates the current line.
#