From a0ff6f532530c59c2d41f11c092b588e4b8b5aa5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 17 Apr 2014 15:24:40 -0600 Subject: [PATCH] Handle 'autoscroll' option in model when setting selected buffer range --- spec/editor-spec.coffee | 23 +++++++++++++++++--- src/cursor.coffee | 31 ++++++--------------------- src/display-buffer.coffee | 44 +++++++++++++++++++++++++++++++++++++++ src/editor.coffee | 20 +++++++++--------- src/selection.coffee | 6 +++++- 5 files changed, 85 insertions(+), 39 deletions(-) diff --git a/spec/editor-spec.coffee b/spec/editor-spec.coffee index 783a0d5fe..dffdd3374 100644 --- a/spec/editor-spec.coffee +++ b/spec/editor-spec.coffee @@ -670,7 +670,6 @@ describe "Editor", -> editor.setHeight(5.5 * 10) editor.setWidth(5.5 * 10) - it "scrolls down when the last cursor gets closer than ::verticalScrollMargin to the bottom of the editor", -> expect(editor.getScrollTop()).toBe 0 expect(editor.getScrollBottom()).toBe 5.5 * 10 @@ -1077,7 +1076,7 @@ describe "Editor", -> expect(selection1).toBe selection expect(selection1.getBufferRange()).toEqual [[2, 2], [3, 3]] - describe "when the preserveFolds option is false (the default)", -> + describe "when the 'preserveFolds' option is false (the default)", -> it "removes folds that contain the selections", -> editor.setSelectedBufferRange([[0,0], [0,0]]) editor.createFold(1, 4) @@ -1091,7 +1090,7 @@ describe "Editor", -> expect(editor.lineForScreenRow(6).fold).toBeUndefined() expect(editor.lineForScreenRow(10).fold).toBeDefined() - describe "when the preserve folds option is true", -> + describe "when the 'preserveFolds' option is true", -> it "does not remove folds that contain the selections", -> editor.setSelectedBufferRange([[0,0], [0,0]]) editor.createFold(1, 4) @@ -1100,6 +1099,24 @@ describe "Editor", -> expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() + describe ".setSelectedBufferRange(range)", -> + describe "when the 'autoscroll' option is true", -> + it "autoscrolls to the selection", -> + editor.manageScrollPosition = true + editor.setLineHeight(10) + editor.setDefaultCharWidth(10) + editor.setHeight(50) + editor.setWidth(50) + expect(editor.getScrollTop()).toBe 0 + + editor.setSelectedBufferRange([[5, 6], [6, 8]], autoscroll: true) + expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 + expect(editor.getScrollRight()).toBe 50 + + editor.setSelectedBufferRange([[6, 6], [6, 8]], autoscroll: true) + expect(editor.getScrollBottom()).toBe (7 + editor.getVerticalScrollMargin()) * 10 + expect(editor.getScrollRight()).toBe (8 + editor.getHorizontalScrollMargin()) * 10 + describe ".selectMarker(marker)", -> describe "if the marker is valid", -> it "selects the marker's range and returns the selected range", -> diff --git a/src/cursor.coffee b/src/cursor.coffee index 6dd8afdcc..1c7de215b 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -59,12 +59,7 @@ class Cursor extends Model @emit 'autoscrolled' if @needsAutoscroll getPixelRect: -> - screenPosition = @getScreenPosition() - {top, left} = @editor.pixelPositionForScreenPosition(screenPosition, false) - right = @editor.pixelPositionForScreenPosition(screenPosition.add([0, 1])).left - width = right - left - height = @editor.getLineHeight() - {top, left, width, height} + @editor.pixelRectForScreenRange(@getScreenRange()) # Public: Moves a cursor to a given screen position. # @@ -81,6 +76,10 @@ class Cursor extends Model getScreenPosition: -> @marker.getHeadScreenPosition() + getScreenRange: -> + {row, column} = @getScreenPosition() + new Range(new Point(row, column), new Point(row, column + 1)) + # Public: Moves a cursor to a given buffer position. # # bufferPosition - An {Array} of two numbers: the buffer row, and the buffer @@ -97,25 +96,7 @@ class Cursor extends Model @marker.getHeadBufferPosition() autoscroll: -> - verticalScrollMarginInPixels = @editor.getVerticalScrollMargin() * @editor.getLineHeight() - horizontalScrollMarginInPixels = @editor.getHorizontalScrollMargin() * @editor.getDefaultCharWidth() - {top, left, height, width} = @getPixelRect() - bottom = top + height - right = left + width - desiredScrollTop = top - verticalScrollMarginInPixels - desiredScrollBottom = bottom + verticalScrollMarginInPixels - desiredScrollLeft = left - horizontalScrollMarginInPixels - desiredScrollRight = right + horizontalScrollMarginInPixels - - if desiredScrollTop < @editor.getScrollTop() - @editor.setScrollTop(desiredScrollTop) - else if desiredScrollBottom > @editor.getScrollBottom() - @editor.setScrollBottom(desiredScrollBottom) - - if desiredScrollLeft < @editor.getScrollLeft() - @editor.setScrollLeft(desiredScrollLeft) - else if desiredScrollRight > @editor.getScrollRight() - @editor.setScrollRight(desiredScrollRight) + @editor.autoscrollToScreenRange(@getScreenRange()) # Public: If the marker range is empty, the cursor is marked as being visible. updateVisibility: -> diff --git a/src/display-buffer.coffee b/src/display-buffer.coffee index 77dd8496d..24e098425 100644 --- a/src/display-buffer.coffee +++ b/src/display-buffer.coffee @@ -30,6 +30,9 @@ class DisplayBuffer extends Model scrollTop: 0 scrollLeft: 0 + verticalScrollMargin: 2 + horizontalScrollMargin: 6 + constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer}={}) -> super @softWrap ?= atom.config.get('editor.softWrap') ? false @@ -102,6 +105,12 @@ class DisplayBuffer extends Model # visible - A {Boolean} indicating of the tokenized buffer is shown setVisible: (visible) -> @tokenizedBuffer.setVisible(visible) + getVerticalScrollMargin: -> @verticalScrollMargin + setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin + + getHorizontalScrollMargin: -> @horizontalScrollMargin + setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin + getHeight: -> @height setHeight: (@height) -> @height @@ -185,6 +194,41 @@ class DisplayBuffer extends Model {start, end} = selection.getScreenRange() @intersectsVisibleRowRange(start.row, end.row + 1) + autoscrollToScreenRange: (screenRange) -> + verticalScrollMarginInPixels = @getVerticalScrollMargin() * @getLineHeight() + horizontalScrollMarginInPixels = @getHorizontalScrollMargin() * @getDefaultCharWidth() + + {top, left, height, width} = @pixelRectForScreenRange(screenRange) + bottom = top + height + right = left + width + desiredScrollTop = top - verticalScrollMarginInPixels + desiredScrollBottom = bottom + verticalScrollMarginInPixels + desiredScrollLeft = left - horizontalScrollMarginInPixels + desiredScrollRight = right + horizontalScrollMarginInPixels + + if desiredScrollTop < @getScrollTop() + @setScrollTop(desiredScrollTop) + else if desiredScrollBottom > @getScrollBottom() + @setScrollBottom(desiredScrollBottom) + + if desiredScrollLeft < @getScrollLeft() + @setScrollLeft(desiredScrollLeft) + else if desiredScrollRight > @getScrollRight() + @setScrollRight(desiredScrollRight) + + pixelRectForScreenRange: (screenRange) -> + if screenRange.end.row > screenRange.start.row + top = @pixelPositionForScreenPosition(screenRange.start).top + left = 0 + height = (screenRange.end.row - screenRange.start.row + 1) * @getLineHeight() + width = @getScrollWidth() + else + {top, left} = @pixelPositionForScreenPosition(screenRange.start) + height = @getLineHeight() + width = @pixelPositionForScreenPosition(screenRange.end).left - left + + {top, left, width, height} + # Retrieves the current tab length. # # Returns a {Number}. diff --git a/src/editor.coffee b/src/editor.coffee index 2fe0b51e8..739e71d3a 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -144,8 +144,6 @@ class Editor extends Model cursors: null selections: null suppressSelectionMerging: false - verticalScrollMargin: 2 - horizontalScrollMargin: 6 @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows', 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', @@ -305,14 +303,6 @@ class Editor extends Model # Public: Toggle soft wrap for this editor toggleSoftWrap: -> @setSoftWrap(not @getSoftWrap()) - getVerticalScrollMargin: -> @verticalScrollMargin - - setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin - - getHorizontalScrollMargin: -> @horizontalScrollMargin - - setHorizontalScrollMargin: (@horizontalScrollMargin) -> @horizontalScrollMargin - # Public: Get the text representing a single level of indent. # # If soft tabs are enabled, the text is composed of N spaces, where N is the @@ -1818,6 +1808,12 @@ class Editor extends Model getSelectionMarkerAttributes: -> type: 'selection', editorId: @id, invalidate: 'never' + getVerticalScrollMargin: -> @displayBuffer.getVerticalScrollMargin() + setVerticalScrollMargin: (args...) -> @displayBuffer.setVerticalScrollMargin(args...) + + getHorizontalScrollMargin: -> @displayBuffer.getHorizontalScrollMargin() + setHorizontalScrollMargin: (args...) -> @displayBuffer.setHorizontalScrollMargin(args...) + getLineHeight: -> @displayBuffer.getLineHeight() setLineHeight: (lineHeight) -> @displayBuffer.setLineHeight(lineHeight) @@ -1864,6 +1860,10 @@ class Editor extends Model screenPositionForPixelPosition: (args...) -> @displayBuffer.screenPositionForPixelPosition(args...) + pixelRectForScreenRange: (args...) -> @displayBuffer.pixelRectForScreenRange(args...) + + autoscrollToScreenRange: (args...) -> @displayBuffer.autoscrollToScreenRange(args...) + # Deprecated: Call {::joinLines} instead. joinLine: -> deprecate("Use Editor::joinLines() instead") diff --git a/src/selection.coffee b/src/selection.coffee index 30694deed..a60374f9e 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -76,8 +76,9 @@ class Selection extends Model options.reversed ?= @isReversed() @editor.destroyFoldsIntersectingBufferRange(bufferRange) unless options.preserveFolds @modifySelection => - @cursor.needsAutoscroll = false if options.autoscroll? + @cursor.needsAutoscroll = false if @needsAutoscroll? @marker.setBufferRange(bufferRange, options) + @autoscroll() if @needsAutoscroll # Public: Returns the starting and ending buffer rows the selection is # highlighting. @@ -90,6 +91,9 @@ class Selection extends Model end = Math.max(start, end - 1) if range.end.column == 0 [start, end] + autoscroll: -> + @editor.autoscrollToScreenRange(@getScreenRange()) + # Public: Returns the text in the selection. getText: -> @editor.buffer.getTextInRange(@getBufferRange())