diff --git a/spec/editor-spec.coffee b/spec/editor-spec.coffee index aca279e2a..3e038f26e 100644 --- a/spec/editor-spec.coffee +++ b/spec/editor-spec.coffee @@ -645,6 +645,38 @@ describe "Editor", -> cursor2 = editor.addCursorAtBufferPosition([1,4]) expect(cursor2.marker).toBe cursor1.marker + describe "autoscroll", -> + beforeEach -> + editor.setVerticalScrollMargin(2) + editor.setLineHeight(10) + editor.setHeight(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 + + editor.setCursorScreenPosition([2, 0]) + expect(editor.getScrollBottom()).toBe 5.5 * 10 + + editor.moveCursorDown() + expect(editor.getScrollBottom()).toBe 6 * 10 + + editor.moveCursorDown() + expect(editor.getScrollBottom()).toBe 7 * 10 + + it "scrolls up when the last cursor gets closer than ::verticalScrollMargin to the top of the editor", -> + editor.setCursorScreenPosition([11, 0]) + editor.setScrollBottom(editor.getScrollHeight()) + + editor.moveCursorUp() + expect(editor.getScrollBottom()).toBe editor.getScrollHeight() + + editor.moveCursorUp() + expect(editor.getScrollTop()).toBe 7 * 10 + + editor.moveCursorUp() + expect(editor.getScrollTop()).toBe 6 * 10 + describe "selection", -> selection = null diff --git a/src/cursor.coffee b/src/cursor.coffee index d361687fa..d496536f7 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -27,7 +27,12 @@ class Cursor {textChanged} = e return if oldHeadScreenPosition.isEqual(newHeadScreenPosition) + # Supports old editor view @needsAutoscroll ?= @isLastCursor() and !textChanged + + # Supports react editor view + @autoscroll() if @needsAutoscroll + @goalColumn = null movedEvent = @@ -92,6 +97,19 @@ class Cursor getBufferPosition: -> @marker.getHeadBufferPosition() + autoscroll: -> + scrollMarginInPixels = @editor.getVerticalScrollMargin() * @editor.getLineHeight() + {top, height} = @getPixelRect() + bottom = top + height + + desiredScrollTop = top - scrollMarginInPixels + desiredScrollBottom = bottom + scrollMarginInPixels + + if desiredScrollTop < @editor.getScrollTop() + @editor.setScrollTop(desiredScrollTop) + else if desiredScrollBottom > @editor.getScrollBottom() + @editor.setScrollBottom(desiredScrollBottom) + # Public: If the marker range is empty, the cursor is marked as being visible. updateVisibility: -> @setVisible(@marker.getBufferRange().isEmpty()) diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 5c8d3a70f..d15b68eaf 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -92,7 +92,9 @@ EditorCompont = React.createClass @subscribe editor.$lineHeight.changes, @requestUpdate listenForDOMEvents: -> - @refs.scrollView.getDOMNode().addEventListener 'mousewheel', @onMousewheel + scrollViewNode = @refs.scrollView.getDOMNode() + scrollViewNode.addEventListener 'mousewheel', @onMousewheel + scrollViewNode.addEventListener 'overflowchanged', @onOverflowChanged @getDOMNode().addEventListener 'focus', @onFocus listenForCustomEvents: -> diff --git a/src/editor.coffee b/src/editor.coffee index 7902ad98f..b44dd4480 100644 --- a/src/editor.coffee +++ b/src/editor.coffee @@ -144,15 +144,16 @@ class Editor extends Model cursors: null selections: null suppressSelectionMerging: false + verticalScrollMargin: 2 @delegatesMethods 'suggestedIndentForBufferRow', 'autoIndentBufferRow', 'autoIndentBufferRows', 'autoDecreaseIndentForBufferRow', 'toggleLineCommentForBufferRow', 'toggleLineCommentsForBufferRows', toProperty: 'languageMode' @delegatesMethods 'setLineHeight', 'getLineHeight', 'setDefaultCharWidth', 'setHeight', - 'getHeight', 'setWidth', 'getWidth', 'setScrollTop', 'getScrollTop', 'setScrollLeft', - 'getScrollLeft', 'getScrollHeight', 'getVisibleRowRange', 'intersectsVisibleRowRange', - 'selectionIntersectsVisibleRowRange', toProperty: 'displayBuffer' + 'getHeight', 'setWidth', 'getWidth', 'setScrollTop', 'getScrollTop', 'getScrollBottom', + 'setScrollBottom', 'setScrollLeft', 'getScrollLeft', 'getScrollHeight', 'getVisibleRowRange', + 'intersectsVisibleRowRange', 'selectionIntersectsVisibleRowRange', toProperty: 'displayBuffer' @delegatesProperties '$lineHeight', '$defaultCharWidth', '$height', '$width', '$scrollTop', '$scrollLeft', toProperty: 'displayBuffer' @@ -308,6 +309,10 @@ class Editor extends Model # Public: Toggle soft wrap for this editor toggleSoftWrap: -> @setSoftWrap(not @getSoftWrap()) + getVerticalScrollMargin: -> @verticalScrollMargin + + setVerticalScrollMargin: (@verticalScrollMargin) -> @verticalScrollMargin + # 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