From 22305f350ffb82679f9457d2b256a4ef722689dd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 27 Feb 2012 12:45:26 -0700 Subject: [PATCH] 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. --- spec/atom/line-folder-spec.coffee | 18 ++++++++--- spec/atom/line-wrapper-spec.coffee | 52 ++++++++++++++++++++++-------- src/atom/cursor.coffee | 7 +--- src/atom/editor.coffee | 4 +-- src/atom/line-folder.coffee | 4 +-- src/atom/line-map.coffee | 16 ++++++--- src/atom/line-wrapper.coffee | 8 +++-- 7 files changed, 74 insertions(+), 35 deletions(-) diff --git a/spec/atom/line-folder-spec.coffee b/spec/atom/line-folder-spec.coffee index 5cd5457cb..cfc1ac2b3 100644 --- a/spec/atom/line-folder-spec.coffee +++ b/spec/atom/line-folder-spec.coffee @@ -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] diff --git a/spec/atom/line-wrapper-spec.coffee b/spec/atom/line-wrapper-spec.coffee index ba0756ae2..0654441eb 100644 --- a/spec/atom/line-wrapper-spec.coffee +++ b/spec/atom/line-wrapper-spec.coffee @@ -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] + diff --git a/src/atom/cursor.coffee b/src/atom/cursor.coffee index 2674d5299..87dfab2cf 100644 --- a/src/atom/cursor.coffee +++ b/src/atom/cursor.coffee @@ -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() diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index 26ca5cd40..d690a4565 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -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 } diff --git a/src/atom/line-folder.coffee b/src/atom/line-folder.coffee index cc2474865..1aa102b70 100644 --- a/src/atom/line-folder.coffee +++ b/src/atom/line-folder.coffee @@ -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) diff --git a/src/atom/line-map.coffee b/src/atom/line-map.coffee index dd933d2b9..f2fb812fe 100644 --- a/src/atom/line-map.coffee +++ b/src/atom/line-map.coffee @@ -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)-> diff --git a/src/atom/line-wrapper.coffee b/src/atom/line-wrapper.coffee index b0b34bd6b..b76b846ef 100644 --- a/src/atom/line-wrapper.coffee +++ b/src/atom/line-wrapper.coffee @@ -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]