Skip fold placeholders when moving right

This relies on a new `eagerWrap` option to clipScreenPosition which
will wrap positions inside of atomic line fragments (which is what fold
placeholders are) to the end of the fragment rather than the beginning.
It also wraps positions beyond the end of a hard line to the next line,
which means Cursor.moveRight just has to increment the column, then
call clipPosition with eager wrap set to true to get all the correct
behavior.
This commit is contained in:
Nathan Sobo 2012-02-27 12:45:26 -07:00
parent c2cba8bdcd
commit 22305f350f
7 changed files with 74 additions and 35 deletions

View File

@ -313,7 +313,7 @@ describe "LineFolder", ->
expect(folder.bufferPositionForScreenPosition([4, 13])).toEqual [4, 15]
expect(folder.bufferPositionForScreenPosition([4, 18])).toEqual [4, 20]
describe ".clipScreenPosition(screenPosition)", ->
describe ".clipScreenPosition(screenPosition, eagerWrap=false)", ->
beforeEach ->
folder.createFold(new Range([4, 29], [7, 4]))
@ -326,10 +326,18 @@ describe "LineFolder", ->
expect(folder.clipScreenPosition([4, 1000])).toEqual [4, 33]
expect(folder.clipScreenPosition([1000, 1000])).toEqual [9, 2]
it "clips positions inside a placeholder to the beginning of the placeholder", ->
expect(folder.clipScreenPosition([4, 30])).toEqual [4, 29]
# expect(folder.clipScreenPosition([4, 31])).toEqual [4, 29]
# expect(folder.clipScreenPosition([4, 32])).toEqual [4, 32]
describe "when eagerWrap is false (the default)", ->
it "clips positions inside a placeholder to the beginning of the placeholder", ->
expect(folder.clipScreenPosition([4, 30])).toEqual [4, 29]
expect(folder.clipScreenPosition([4, 31])).toEqual [4, 29]
expect(folder.clipScreenPosition([4, 32])).toEqual [4, 32]
describe "when eagerWrap is true", ->
it "clips positions inside a placeholder to the end of the placeholder", ->
expect(folder.clipScreenPosition([4, 29], true)).toEqual [4, 29]
expect(folder.clipScreenPosition([4, 30], true)).toEqual [4, 32]
expect(folder.clipScreenPosition([4, 31], true)).toEqual [4, 32]
expect(folder.clipScreenPosition([4, 32], true)).toEqual [4, 32]

View File

@ -237,21 +237,45 @@ describe "LineWrapper", ->
expect(line2.endColumn).toBe 14
expect(line2.text.length).toBe 3
describe ".clipScreenPosition(screenPosition)", ->
it "returns the nearest valid position based on the current screen lines", ->
expect(wrapper.clipScreenPosition([-1, -1])).toEqual [0, 0]
expect(wrapper.clipScreenPosition([0, -1])).toEqual [0, 0]
expect(wrapper.clipScreenPosition([1, 10000])).toEqual [1, 30]
expect(wrapper.clipScreenPosition([3, 51])).toEqual [4, 0]
expect(wrapper.clipScreenPosition([3, 58])).toEqual [4, 0]
describe ".clipScreenPosition(screenPosition, eagerWrap=false)", ->
it "allows valid positions", ->
expect(wrapper.clipScreenPosition([4, 5])).toEqual [4, 5]
expect(wrapper.clipScreenPosition([4, 11])).toEqual [4, 11]
expect(wrapper.clipScreenPosition([4, 30])).toEqual [4, 11]
expect(wrapper.clipScreenPosition([4, 1000])).toEqual [4, 11]
it "disallows negative positions", ->
expect(wrapper.clipScreenPosition([-1, -1])).toEqual [0, 0]
expect(wrapper.clipScreenPosition([0, -1])).toEqual [0, 0]
it "disallows positions beyond the last row", ->
expect(wrapper.clipScreenPosition([1000, 0])).toEqual [15, 2]
expect(wrapper.clipScreenPosition([1000, 1000])).toEqual [15, 2]
it "also clips the screen position with respect to fold placeholders", ->
folder.createFold(new Range([3, 55], [3, 59]))
expect(wrapper.clipScreenPosition([4, 5])).toEqual [4, 4]
expect(wrapper.clipScreenPosition([4, 6])).toEqual [4, 4]
it "wraps positions at the end of soft-wrapped lines to the next screen line", ->
expect(wrapper.clipScreenPosition([3, 51])).toEqual [4, 0]
expect(wrapper.clipScreenPosition([3, 58])).toEqual [4, 0]
expect(wrapper.clipScreenPosition([3, 1000])).toEqual [4, 0]
describe "when eagerWrap is false (the default)", ->
it "wraps positions beyond the end of hard lines to the end of the line", ->
expect(wrapper.clipScreenPosition([1, 10000])).toEqual [1, 30]
expect(wrapper.clipScreenPosition([4, 30])).toEqual [4, 11]
expect(wrapper.clipScreenPosition([4, 1000])).toEqual [4, 11]
it "clips screen positions in the middle of fold placeholders to the to the beginning of fold placeholders", ->
folder.createFold(new Range([3, 55], [3, 59]))
expect(wrapper.clipScreenPosition([4, 5])).toEqual [4, 4]
expect(wrapper.clipScreenPosition([4, 6])).toEqual [4, 4]
expect(wrapper.clipScreenPosition([4, 7])).toEqual [4, 7]
describe "when eagerWrap is true", ->
it "wraps positions past the end of non-softwrapped lines to the next line", ->
expect(wrapper.clipScreenPosition([0, 29], true)).toEqual [0, 29]
expect(wrapper.clipScreenPosition([0, 30], true)).toEqual [1, 0]
expect(wrapper.clipScreenPosition([0, 1000], true)).toEqual [1, 0]
it "wraps the screen positions in the middle of fold placeholders to the end of the placeholder", ->
folder.createFold(new Range([3, 55], [3, 59]))
expect(wrapper.clipScreenPosition([4, 4], true)).toEqual [4, 4]
expect(wrapper.clipScreenPosition([4, 5], true)).toEqual [4, 7]
expect(wrapper.clipScreenPosition([4, 6], true)).toEqual [4, 7]

View File

@ -77,12 +77,7 @@ class Cursor extends View
moveRight: ->
{ row, column } = @getScreenPosition()
if column < @editor.buffer.getLine(row).length
column++
else if row < @editor.buffer.numLines() - 1
row++
column = 0
@setScreenPosition({row, column})
@setScreenPosition(@editor.clipScreenPosition([row, column + 1], true))
moveLeft: ->
{ row, column } = @getScreenPosition()

View File

@ -211,8 +211,8 @@ class Editor extends View
else
$(window).off 'resize', @_setMaxLineLength
clipScreenPosition: (screenPosition) ->
@lineWrapper.clipScreenPosition(screenPosition)
clipScreenPosition: (screenPosition, eagerWrap=false) ->
@lineWrapper.clipScreenPosition(screenPosition, eagerWrap)
pixelPositionForScreenPosition: ({row, column}) ->
{ top: row * @lineHeight, left: column * @charWidth }

View File

@ -134,8 +134,8 @@ class LineFolder
bufferPositionForScreenPosition: (screenPosition) ->
@lineMap.bufferPositionForScreenPosition(screenPosition)
clipScreenPosition: (screenPosition) ->
@lineMap.clipScreenPosition(screenPosition)
clipScreenPosition: (screenPosition, eagerWrap=false) ->
@lineMap.clipScreenPosition(screenPosition, eagerWrap)
screenRangeForBufferRange: (bufferRange) ->
@lineMap.screenRangeForBufferRange(bufferRange)

View File

@ -141,10 +141,9 @@ class LineMap
end = @bufferPositionForScreenPosition(screenRange.end)
new Range(start, end)
clipScreenPosition: (screenPosition) ->
clipScreenPosition: (screenPosition, eagerWrap) ->
screenPosition = Point.fromObject(screenPosition)
debugger if screenPosition.isEqual [7,4]
screenPosition = new Point(Math.max(0, screenPosition.row), Math.max(0, screenPosition.column))
maxRow = @lastScreenRow()
if screenPosition.row > maxRow
@ -157,8 +156,17 @@ class LineMap
break if nextDelta.isGreaterThan(screenPosition)
screenDelta = nextDelta
maxColumn = screenDelta.column + screenLine.lengthForClipping()
screenDelta.column = Math.min(maxColumn, screenPosition.column)
if screenLine.isAtomic
if eagerWrap and screenPosition.column > screenDelta.column
screenDelta.column = screenDelta.column + screenLine.text.length
else
maxColumn = screenDelta.column + screenLine.text.length
if eagerWrap and screenPosition.column > maxColumn
screenDelta.row++
screenDelta.column = 0
else
screenDelta.column = Math.min(maxColumn, screenPosition.column)
screenDelta
logLines: (start=0, end=@screenLineCount() - 1)->

View File

@ -93,11 +93,15 @@ class LineWrapper
@lineFolder.bufferRangeForScreenRange(
@lineMap.bufferRangeForScreenRange(screenRange))
clipScreenPosition: (screenPosition) ->
clipScreenPosition: (screenPosition, eagerWrap=false) ->
@lineMap.screenPositionForBufferPosition(
@lineFolder.clipScreenPosition(
@lineMap.bufferPositionForScreenPosition(
@lineMap.clipScreenPosition(screenPosition))))
@lineMap.clipScreenPosition(screenPosition, eagerWrap)
),
eagerWrap
)
)
lineForScreenRow: (screenRow) ->
@linesForScreenRows(screenRow, screenRow)[0]