mirror of
https://github.com/atom/atom.git
synced 2026-01-23 05:48:10 -05:00
Merge pull request #5959 from atom/as-fix-select-above-below
Use screen ranges to select above and below
This commit is contained in:
@@ -1626,7 +1626,54 @@ describe "TextEditor", ->
|
||||
[[6, 22], [6, 28]]
|
||||
]
|
||||
|
||||
it "can add selections to soft-wrapped line segments", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
editor.setSelectedScreenRange([[3, 10], [3, 15]])
|
||||
editor.addSelectionBelow()
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[3, 10], [3, 15]]
|
||||
[[4, 10], [4, 15]]
|
||||
]
|
||||
|
||||
it "takes atomic tokens into account", ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRange([[2, 1], [2, 3]])
|
||||
editor.addSelectionBelow()
|
||||
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [
|
||||
[[2, 1], [2, 3]]
|
||||
[[3, 1], [3, 2]]
|
||||
]
|
||||
|
||||
describe "when the selection is empty", ->
|
||||
describe "when lines are soft-wrapped", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
it "skips soft-wrap indentation tokens", ->
|
||||
editor.setCursorScreenPosition([3, 0])
|
||||
editor.addSelectionBelow()
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[3, 0], [3, 0]]
|
||||
[[4, 4], [4, 4]]
|
||||
]
|
||||
|
||||
it "does not skip them if they're shorter than the current column", ->
|
||||
editor.setCursorScreenPosition([3, 37])
|
||||
editor.addSelectionBelow()
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[3, 37], [3, 37]]
|
||||
[[4, 26], [4, 26]]
|
||||
]
|
||||
|
||||
it "does not skip lines that are shorter than the current column", ->
|
||||
editor.setCursorBufferPosition([3, 36])
|
||||
editor.addSelectionBelow()
|
||||
@@ -1690,7 +1737,54 @@ describe "TextEditor", ->
|
||||
[[3, 22], [3, 38]]
|
||||
]
|
||||
|
||||
it "can add selections to soft-wrapped line segments", ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
editor.setSelectedScreenRange([[4, 10], [4, 15]])
|
||||
editor.addSelectionAbove()
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[4, 10], [4, 15]]
|
||||
[[3, 10], [3, 15]]
|
||||
]
|
||||
|
||||
it "takes atomic tokens into account", ->
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-tabs-and-leading-comment.coffee', autoIndent: false).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.setSelectedBufferRange([[3, 1], [3, 2]])
|
||||
editor.addSelectionAbove()
|
||||
|
||||
expect(editor.getSelectedBufferRanges()).toEqual [
|
||||
[[3, 1], [3, 2]]
|
||||
[[2, 1], [2, 3]]
|
||||
]
|
||||
|
||||
describe "when the selection is empty", ->
|
||||
describe "when lines are soft-wrapped", ->
|
||||
beforeEach ->
|
||||
editor.setSoftWrapped(true)
|
||||
editor.setEditorWidthInChars(40)
|
||||
|
||||
it "skips soft-wrap indentation tokens", ->
|
||||
editor.setCursorScreenPosition([5, 0])
|
||||
editor.addSelectionAbove()
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[5, 0], [5, 0]]
|
||||
[[4, 4], [4, 4]]
|
||||
]
|
||||
|
||||
it "does not skip them if they're shorter than the current column", ->
|
||||
editor.setCursorScreenPosition([5, 29])
|
||||
editor.addSelectionAbove()
|
||||
|
||||
expect(editor.getSelectedScreenRanges()).toEqual [
|
||||
[[5, 29], [5, 29]]
|
||||
[[4, 26], [4, 26]]
|
||||
]
|
||||
|
||||
it "does not skip lines that are shorter than the current column", ->
|
||||
editor.setCursorBufferPosition([6, 36])
|
||||
editor.addSelectionAbove()
|
||||
|
||||
@@ -859,6 +859,18 @@ class DisplayBuffer extends Model
|
||||
column = screenLine.clipScreenColumn(column, options)
|
||||
new Point(row, column)
|
||||
|
||||
# Clip the start and end of the given range to valid positions on screen.
|
||||
# See {::clipScreenPosition} for more information.
|
||||
#
|
||||
# * `range` The {Range} to clip.
|
||||
# * `options` (optional) See {::clipScreenPosition} `options`.
|
||||
# Returns a {Range}.
|
||||
clipScreenRange: (range, options) ->
|
||||
start = @clipScreenPosition(range.start, options)
|
||||
end = @clipScreenPosition(range.end, options)
|
||||
|
||||
new Range(start, end)
|
||||
|
||||
# Calculates a {Range} representing the start of the {TextBuffer} until the end.
|
||||
#
|
||||
# Returns a {Range}.
|
||||
|
||||
@@ -183,7 +183,7 @@ class Selection extends Model
|
||||
|
||||
# Public: Clears the selection, moving the marker to the head.
|
||||
clear: ->
|
||||
@marker.setProperties(goalBufferRange: null)
|
||||
@marker.setProperties(goalScreenRange: null)
|
||||
@marker.clearTail() unless @retainSelection
|
||||
@finalize()
|
||||
|
||||
@@ -656,38 +656,38 @@ class Selection extends Model
|
||||
|
||||
# Public: Moves the selection down one row.
|
||||
addSelectionBelow: ->
|
||||
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
|
||||
range = (@getGoalScreenRange() ? @getScreenRange()).copy()
|
||||
nextRow = range.end.row + 1
|
||||
|
||||
for row in [nextRow..@editor.getLastBufferRow()]
|
||||
for row in [nextRow..@editor.getLastScreenRow()]
|
||||
range.start.row = row
|
||||
range.end.row = row
|
||||
clippedRange = @editor.clipBufferRange(range)
|
||||
clippedRange = @editor.clipScreenRange(range, skipSoftWrapIndentation: true)
|
||||
|
||||
if range.isEmpty()
|
||||
continue if range.end.column > 0 and clippedRange.end.column is 0
|
||||
else
|
||||
continue if clippedRange.isEmpty()
|
||||
|
||||
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
|
||||
@editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range)
|
||||
break
|
||||
|
||||
# Public: Moves the selection up one row.
|
||||
addSelectionAbove: ->
|
||||
range = (@getGoalBufferRange() ? @getBufferRange()).copy()
|
||||
range = (@getGoalScreenRange() ? @getScreenRange()).copy()
|
||||
previousRow = range.end.row - 1
|
||||
|
||||
for row in [previousRow..0]
|
||||
range.start.row = row
|
||||
range.end.row = row
|
||||
clippedRange = @editor.clipBufferRange(range)
|
||||
clippedRange = @editor.clipScreenRange(range, skipSoftWrapIndentation: true)
|
||||
|
||||
if range.isEmpty()
|
||||
continue if range.end.column > 0 and clippedRange.end.column is 0
|
||||
else
|
||||
continue if clippedRange.isEmpty()
|
||||
|
||||
@editor.addSelectionForBufferRange(range, goalBufferRange: range)
|
||||
@editor.addSelectionForScreenRange(clippedRange, goalScreenRange: range)
|
||||
break
|
||||
|
||||
# Public: Combines the given selection into this selection and then destroys
|
||||
@@ -696,12 +696,14 @@ class Selection extends Model
|
||||
# * `otherSelection` A {Selection} to merge with.
|
||||
# * `options` (optional) {Object} options matching those found in {::setBufferRange}.
|
||||
merge: (otherSelection, options) ->
|
||||
myGoalBufferRange = @getGoalBufferRange()
|
||||
otherGoalBufferRange = otherSelection.getGoalBufferRange()
|
||||
if myGoalBufferRange? and otherGoalBufferRange?
|
||||
options.goalBufferRange = myGoalBufferRange.union(otherGoalBufferRange)
|
||||
myGoalScreenRange = @getGoalScreenRange()
|
||||
otherGoalScreenRange = otherSelection.getGoalScreenRange()
|
||||
|
||||
if myGoalScreenRange? and otherGoalScreenRange?
|
||||
options.goalScreenRange = myGoalScreenRange.union(otherGoalScreenRange)
|
||||
else
|
||||
options.goalBufferRange = myGoalBufferRange ? otherGoalBufferRange
|
||||
options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange
|
||||
|
||||
@setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), options)
|
||||
otherSelection.destroy()
|
||||
|
||||
@@ -763,6 +765,6 @@ class Selection extends Model
|
||||
plantTail: ->
|
||||
@marker.plantTail()
|
||||
|
||||
getGoalBufferRange: ->
|
||||
if goalBufferRange = @marker.getProperties().goalBufferRange
|
||||
Range.fromObject(goalBufferRange)
|
||||
getGoalScreenRange: ->
|
||||
if goalScreenRange = @marker.getProperties().goalScreenRange
|
||||
Range.fromObject(goalScreenRange)
|
||||
|
||||
@@ -1275,6 +1275,14 @@ class TextEditor extends Model
|
||||
# Returns a {Point}.
|
||||
clipScreenPosition: (screenPosition, options) -> @displayBuffer.clipScreenPosition(screenPosition, options)
|
||||
|
||||
# Extended: Clip the start and end of the given range to valid positions on screen.
|
||||
# See {::clipScreenPosition} for more information.
|
||||
#
|
||||
# * `range` The {Range} to clip.
|
||||
# * `options` (optional) See {::clipScreenPosition} `options`.
|
||||
# Returns a {Range}.
|
||||
clipScreenRange: (range, options) -> @displayBuffer.clipScreenRange(range, options)
|
||||
|
||||
###
|
||||
Section: Decorations
|
||||
###
|
||||
|
||||
Reference in New Issue
Block a user