Merge pull request #9444 from atom/mb-synchronous-scroll-position

Allow synchronous control of scroll position through TextEditor model
This commit is contained in:
Max Brunsfeld
2015-11-11 09:58:05 -08:00
5 changed files with 202 additions and 83 deletions

View File

@@ -25,27 +25,34 @@ describe "TextEditorPresenter", ->
editor.destroy()
buffer.destroy()
buildPresenter = (params={}) ->
buildPresenterWithoutMeasurements = (params={}) ->
_.defaults params,
model: editor
explicitHeight: 130
contentFrameWidth: 500
windowWidth: 500
windowHeight: 130
boundingClientRect: {left: 0, top: 0, width: 500, height: 130}
gutterWidth: 0
lineHeight: 10
baseCharacterWidth: 10
horizontalScrollbarHeight: 10
verticalScrollbarWidth: 10
scrollTop: 0
scrollLeft: 0
config: atom.config
contentFrameWidth: 500
presenter = new TextEditorPresenter(params)
presenter.setLinesYardstick(new FakeLinesYardstick(editor, presenter))
presenter
buildPresenter = (params={}) ->
presenter = buildPresenterWithoutMeasurements(params)
presenter.setScrollTop(params.scrollTop) if params.scrollTop?
presenter.setScrollLeft(params.scrollLeft) if params.scrollLeft?
presenter.setExplicitHeight(params.explicitHeight ? 130)
presenter.setWindowSize(params.windowWidth ? 500, params.windowHeight ? 130)
presenter.setBoundingClientRect(params.boundingClientRect ? {
left: 0
top: 0
width: 500
height: 130
})
presenter.setGutterWidth(params.gutterWidth ? 0)
presenter.setLineHeight(params.lineHeight ? 10)
presenter.setBaseCharacterWidth(params.baseCharacterWidth ? 10)
presenter.setHorizontalScrollbarHeight(params.horizontalScrollbarHeight ? 10)
presenter.setVerticalScrollbarWidth(params.verticalScrollbarWidth ? 10)
presenter
expectValues = (actual, expected) ->
for key, value of expected
expect(actual[key]).toEqual value
@@ -167,16 +174,14 @@ describe "TextEditorPresenter", ->
expect(stateFn(presenter).tiles[12]).toBeDefined()
it "is empty until all of the required measurements are assigned", ->
presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null)
presenter = buildPresenterWithoutMeasurements()
expect(stateFn(presenter).tiles).toEqual({})
presenter.setExplicitHeight(25)
expect(stateFn(presenter).tiles).toEqual({})
# Sets scroll row from model's logical position
presenter.setLineHeight(10)
expect(stateFn(presenter).tiles).toEqual({})
presenter.setScrollTop(0)
expect(stateFn(presenter).tiles).not.toEqual({})
it "updates when ::scrollTop changes", ->
@@ -619,6 +624,8 @@ describe "TextEditorPresenter", ->
describe ".scrollingVertically", ->
it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", ->
presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200, explicitHeight: 100)
expect(presenter.getState().content.scrollingVertically).toBe true
advanceClock(300)
expect(presenter.getState().content.scrollingVertically).toBe false
expectStateUpdate presenter, -> presenter.setScrollTop(0)
expect(presenter.getState().content.scrollingVertically).toBe true
@@ -761,7 +768,8 @@ describe "TextEditorPresenter", ->
expect(presenter.getState().content.scrollTop).toBe(10)
it "corresponds to the passed logical coordinates when building the presenter", ->
presenter = buildPresenter(scrollRow: 4, lineHeight: 10, explicitHeight: 20)
editor.setFirstVisibleScreenRow(4)
presenter = buildPresenter(lineHeight: 10, explicitHeight: 20)
expect(presenter.getState().content.scrollTop).toBe(40)
it "tracks the value of ::scrollTop", ->
@@ -775,11 +783,11 @@ describe "TextEditorPresenter", ->
expectStateUpdate presenter, -> presenter.setScrollTop(50)
presenter.getState() # commits scroll position
expect(editor.getScrollRow()).toBe(5)
expect(editor.getFirstVisibleScreenRow()).toBe 5
expectStateUpdate presenter, -> presenter.setScrollTop(57)
presenter.getState() # commits scroll position
expect(editor.getScrollRow()).toBe(6)
expect(editor.getFirstVisibleScreenRow()).toBe 6
it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", ->
presenter = buildPresenter(scrollTop: 80, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 0)
@@ -888,7 +896,8 @@ describe "TextEditorPresenter", ->
expect(presenter.getState().content.scrollLeft).toBe(50)
it "corresponds to the passed logical coordinates when building the presenter", ->
presenter = buildPresenter(scrollColumn: 3, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
editor.setFirstVisibleScreenColumn(3)
presenter = buildPresenter(lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
expect(presenter.getState().content.scrollLeft).toBe(30)
it "tracks the value of ::scrollLeft", ->
@@ -902,11 +911,11 @@ describe "TextEditorPresenter", ->
expectStateUpdate presenter, -> presenter.setScrollLeft(50)
presenter.getState() # commits scroll position
expect(editor.getScrollColumn()).toBe(5)
expect(editor.getFirstVisibleScreenColumn()).toBe 5
expectStateUpdate presenter, -> presenter.setScrollLeft(57)
presenter.getState() # commits scroll position
expect(editor.getScrollColumn()).toBe(6)
expect(editor.getFirstVisibleScreenColumn()).toBe 6
it "is always rounded to the nearest integer", ->
presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500)
@@ -1006,20 +1015,25 @@ describe "TextEditorPresenter", ->
describe ".backgroundColor", ->
it "is assigned to ::backgroundColor unless the editor is mini", ->
presenter = buildPresenter(backgroundColor: 'rgba(255, 0, 0, 0)')
presenter = buildPresenter()
presenter.setBackgroundColor('rgba(255, 0, 0, 0)')
expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)'
editor.setMini(true)
presenter = buildPresenter(backgroundColor: 'rgba(255, 0, 0, 0)')
presenter = buildPresenter()
presenter.setBackgroundColor('rgba(255, 0, 0, 0)')
expect(presenter.getState().content.backgroundColor).toBeNull()
it "updates when ::backgroundColor changes", ->
presenter = buildPresenter(backgroundColor: 'rgba(255, 0, 0, 0)')
presenter = buildPresenter()
presenter.setBackgroundColor('rgba(255, 0, 0, 0)')
expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)'
expectStateUpdate presenter, -> presenter.setBackgroundColor('rgba(0, 0, 255, 0)')
expect(presenter.getState().content.backgroundColor).toBe 'rgba(0, 0, 255, 0)'
it "updates when ::mini changes", ->
presenter = buildPresenter(backgroundColor: 'rgba(255, 0, 0, 0)')
presenter = buildPresenter()
presenter.setBackgroundColor('rgba(255, 0, 0, 0)')
expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)'
expectStateUpdate presenter, -> editor.setMini(true)
expect(presenter.getState().content.backgroundColor).toBeNull()
@@ -1047,6 +1061,7 @@ describe "TextEditorPresenter", ->
describe "[tileId].lines[lineId]", -> # line state objects
it "includes the state for visible lines in a tile", ->
presenter = buildPresenter(explicitHeight: 3, scrollTop: 4, lineHeight: 1, tileSize: 3, stoppedScrollingDelay: 200)
presenter.setExplicitHeight(3)
expect(lineStateForScreenRow(presenter, 2)).toBeUndefined()
@@ -1320,7 +1335,7 @@ describe "TextEditorPresenter", ->
expect(stateForCursor(presenter, 4)).toBeUndefined()
it "is empty until all of the required measurements are assigned", ->
presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, baseCharacterWidth: null, horizontalScrollbarHeight: null)
presenter = buildPresenterWithoutMeasurements()
expect(presenter.getState().content.cursors).toEqual({})
presenter.setExplicitHeight(25)
@@ -1335,6 +1350,15 @@ describe "TextEditorPresenter", ->
presenter.setBaseCharacterWidth(8)
expect(presenter.getState().content.cursors).toEqual({})
presenter.setBoundingClientRect(top: 0, left: 0, width: 500, height: 130)
expect(presenter.getState().content.cursors).toEqual({})
presenter.setWindowSize(500, 130)
expect(presenter.getState().content.cursors).toEqual({})
presenter.setVerticalScrollbarWidth(10)
expect(presenter.getState().content.cursors).toEqual({})
presenter.setHorizontalScrollbarHeight(10)
expect(presenter.getState().content.cursors).not.toEqual({})
@@ -1466,7 +1490,8 @@ describe "TextEditorPresenter", ->
it "alternates between true and false twice per ::cursorBlinkPeriod when the editor is focused", ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay, focused: true})
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay})
presenter.setFocused(true)
expect(presenter.getState().content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
@@ -1493,7 +1518,8 @@ describe "TextEditorPresenter", ->
it "stops alternating for ::cursorBlinkResumeDelay when a cursor moves or a cursor is added", ->
cursorBlinkPeriod = 100
cursorBlinkResumeDelay = 200
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay, focused: true})
presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay})
presenter.setFocused(true)
expect(presenter.getState().content.cursorsVisible).toBe true
expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2)
@@ -1643,7 +1669,7 @@ describe "TextEditorPresenter", ->
[[0, 2], [2, 4]],
])
presenter = buildPresenter(explicitHeight: null, lineHeight: null, scrollTop: null, baseCharacterWidth: null, tileSize: 2)
presenter = buildPresenterWithoutMeasurements(tileSize: 2)
for tileId, tileState of presenter.getState().content.tiles
expect(tileState.highlights).toEqual({})
@@ -1970,7 +1996,7 @@ describe "TextEditorPresenter", ->
marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch')
decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item})
presenter = buildPresenter(baseCharacterWidth: null, lineHeight: null, windowWidth: null, windowHeight: null, boundingClientRect: null)
presenter = buildPresenterWithoutMeasurements()
expect(presenter.getState().content.overlays).toEqual({})
presenter.setBaseCharacterWidth(10)
@@ -1982,6 +2008,12 @@ describe "TextEditorPresenter", ->
presenter.setWindowSize(500, 100)
expect(presenter.getState().content.overlays).toEqual({})
presenter.setVerticalScrollbarWidth(10)
expect(presenter.getState().content.overlays).toEqual({})
presenter.setHorizontalScrollbarHeight(10)
expect(presenter.getState().content.overlays).toEqual({})
presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500})
expect(presenter.getState().content.overlays).not.toEqual({})
@@ -2168,7 +2200,8 @@ describe "TextEditorPresenter", ->
expect(editor.getRowsPerPage()).toBe(20)
it "tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically", ->
presenter = buildPresenter(explicitHeight: null, autoHeight: true)
presenter = buildPresenter(explicitHeight: null)
presenter.setAutoHeight(true)
expect(presenter.getState().height).toBe editor.getScreenLineCount() * 10
expectStateUpdate presenter, -> presenter.setAutoHeight(false)
@@ -2185,7 +2218,9 @@ describe "TextEditorPresenter", ->
describe ".focused", ->
it "tracks the value of ::focused", ->
presenter = buildPresenter(focused: false)
presenter = buildPresenter()
presenter.setFocused(false)
expect(presenter.getState().focused).toBe false
expectStateUpdate presenter, -> presenter.setFocused(true)
expect(presenter.getState().focused).toBe true
@@ -2882,7 +2917,9 @@ describe "TextEditorPresenter", ->
describe ".backgroundColor", ->
it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", ->
presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)")
presenter = buildPresenter()
presenter.setBackgroundColor("rgba(255, 0, 0, 0)")
presenter.setGutterBackgroundColor("rgba(0, 255, 0, 0)")
expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 255, 0, 0)"
expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 255, 0, 0)"

View File

@@ -5444,6 +5444,73 @@ describe "TextEditor", ->
editor.selectPageUp()
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [12, 2]]]
describe "::setFirstVisibleScreenRow() and ::getFirstVisibleScreenRow()", ->
beforeEach ->
line = Array(9).join('0123456789')
editor.setText([1..100].map(-> line).join('\n'))
expect(editor.getLineCount()).toBe 100
expect(editor.lineTextForBufferRow(0).length).toBe 80
describe "when the editor doesn't have a height and lineHeightInPixels", ->
it "does not affect the editor's visible row range", ->
expect(editor.getVisibleRowRange()).toBeNull()
editor.setFirstVisibleScreenRow(1)
expect(editor.getFirstVisibleScreenRow()).toEqual 1
editor.setFirstVisibleScreenRow(3)
expect(editor.getFirstVisibleScreenRow()).toEqual 3
expect(editor.getVisibleRowRange()).toBeNull()
expect(editor.getLastVisibleScreenRow()).toBeNull()
describe "when the editor has a height and lineHeightInPixels", ->
beforeEach ->
atom.config.set('editor.scrollPastEnd', true)
editor.setHeight(100, true)
editor.setLineHeightInPixels(10)
it "updates the editor's visible row range", ->
editor.setFirstVisibleScreenRow(2)
expect(editor.getFirstVisibleScreenRow()).toEqual 2
expect(editor.getLastVisibleScreenRow()).toBe 12
expect(editor.getVisibleRowRange()).toEqual [2, 12]
it "notifies ::onDidChangeFirstVisibleScreenRow observers", ->
changeCount = 0
editor.onDidChangeFirstVisibleScreenRow -> changeCount++
editor.setFirstVisibleScreenRow(2)
expect(changeCount).toBe 1
editor.setFirstVisibleScreenRow(2)
expect(changeCount).toBe 1
editor.setFirstVisibleScreenRow(3)
expect(changeCount).toBe 2
it "ensures that the top row is less than the buffer's line count", ->
editor.setFirstVisibleScreenRow(102)
expect(editor.getFirstVisibleScreenRow()).toEqual 99
expect(editor.getVisibleRowRange()).toEqual [99, 99]
it "ensures that the left column is less than the length of the longest screen line", ->
editor.setFirstVisibleScreenRow(10)
expect(editor.getFirstVisibleScreenRow()).toEqual 10
editor.setText("\n\n\n")
editor.setFirstVisibleScreenRow(10)
expect(editor.getFirstVisibleScreenRow()).toEqual 3
describe "when the 'editor.scrollPastEnd' option is set to false", ->
it "ensures that the bottom row is less than the buffer's line count", ->
atom.config.set('editor.scrollPastEnd', false)
editor.setFirstVisibleScreenRow(95)
expect(editor.getFirstVisibleScreenRow()).toEqual 89
expect(editor.getVisibleRowRange()).toEqual [89, 99]
describe '.get/setPlaceholderText()', ->
it 'can be created with placeholderText', ->
newEditor = atom.workspace.buildTextEditor(

View File

@@ -50,10 +50,6 @@ class TextEditorComponent
@presenter = new TextEditorPresenter
model: @editor
scrollTop: 0
scrollLeft: 0
scrollRow: @editor.getScrollRow()
scrollColumn: @editor.getScrollColumn()
tileSize: tileSize
cursorBlinkPeriod: @cursorBlinkPeriod
cursorBlinkResumeDelay: @cursorBlinkResumeDelay

View File

@@ -13,15 +13,12 @@ class TextEditorPresenter
minimumReflowInterval: 200
constructor: (params) ->
{@model, @config, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @scrollColumn, @scrollRow, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params
{horizontalScrollbarHeight, verticalScrollbarWidth} = params
{@lineHeight, @baseCharacterWidth, @backgroundColor, @gutterBackgroundColor, @tileSize} = params
{@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @focused} = params
@measuredHorizontalScrollbarHeight = horizontalScrollbarHeight
@measuredVerticalScrollbarWidth = verticalScrollbarWidth
@gutterWidth ?= 0
@tileSize ?= 6
{@model, @config} = params
{@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params
{@contentFrameWidth} = params
@gutterWidth = 0
@tileSize ?= 6
@realScrollTop = @scrollTop
@realScrollLeft = @scrollLeft
@disposables = new CompositeDisposable
@@ -77,7 +74,6 @@ class TextEditorPresenter
@updateVerticalDimensions()
@updateScrollbarDimensions()
@restoreScrollPosition()
@commitPendingLogicalScrollTopPosition()
@commitPendingScrollTopPosition()
@@ -218,6 +214,7 @@ class TextEditorPresenter
@disposables.add @model.onDidAddCursor(@didAddCursor.bind(this))
@disposables.add @model.onDidRequestAutoscroll(@requestAutoscroll.bind(this))
@disposables.add @model.onDidChangeFirstVisibleScreenRow(@didChangeFirstVisibleScreenRow.bind(this))
@observeCursor(cursor) for cursor in @model.getCursors()
@disposables.add @model.onDidAddGutter(@didAddGutter.bind(this))
return
@@ -778,8 +775,7 @@ class TextEditorPresenter
if scrollTop isnt @realScrollTop and not Number.isNaN(scrollTop)
@realScrollTop = scrollTop
@scrollTop = Math.round(scrollTop)
@scrollRow = Math.round(@scrollTop / @lineHeight)
@model.setScrollRow(@scrollRow)
@model.setFirstVisibleScreenRow(Math.round(@scrollTop / @lineHeight), true)
@updateStartRow()
@updateEndRow()
@@ -795,8 +791,7 @@ class TextEditorPresenter
if scrollLeft isnt @realScrollLeft and not Number.isNaN(scrollLeft)
@realScrollLeft = scrollLeft
@scrollLeft = Math.round(scrollLeft)
@scrollColumn = Math.round(@scrollLeft / @baseCharacterWidth)
@model.setScrollColumn(@scrollColumn)
@model.setFirstVisibleScreenColumn(Math.round(@scrollLeft / @baseCharacterWidth))
@emitter.emit 'did-change-scroll-left', @scrollLeft
@@ -1095,6 +1090,7 @@ class TextEditorPresenter
setLineHeight: (lineHeight) ->
unless @lineHeight is lineHeight
@lineHeight = lineHeight
@restoreScrollTopIfNeeded()
@model.setLineHeightInPixels(lineHeight)
@shouldUpdateHeightState = true
@shouldUpdateHorizontalScrollState = true
@@ -1122,6 +1118,7 @@ class TextEditorPresenter
@halfWidthCharWidth = halfWidthCharWidth
@koreanCharWidth = koreanCharWidth
@model.setDefaultCharWidth(baseCharacterWidth, doubleWidthCharWidth, halfWidthCharWidth, koreanCharWidth)
@restoreScrollLeftIfNeeded()
@characterWidthsChanged()
characterWidthsChanged: ->
@@ -1433,6 +1430,9 @@ class TextEditorPresenter
@emitDidUpdateState()
didChangeFirstVisibleScreenRow: (screenRow) ->
@updateScrollTop(screenRow * @lineHeight)
getVerticalScrollMarginInPixels: ->
Math.round(@model.getVerticalScrollMargin() * @lineHeight)
@@ -1512,14 +1512,6 @@ class TextEditorPresenter
@updateScrollTop(@pendingScrollTop)
@pendingScrollTop = null
restoreScrollPosition: ->
return if @hasRestoredScrollPosition or not @hasPixelPositionRequirements()
@setScrollTop(@scrollRow * @lineHeight) if @scrollRow?
@setScrollLeft(@scrollColumn * @baseCharacterWidth) if @scrollColumn?
@hasRestoredScrollPosition = true
clearPendingScrollPosition: ->
@pendingScrollLogicalPosition = null
@pendingScrollTop = null
@@ -1531,6 +1523,14 @@ class TextEditorPresenter
canScrollTopTo: (scrollTop) ->
@scrollTop isnt @constrainScrollTop(scrollTop)
restoreScrollTopIfNeeded: ->
unless @scrollTop?
@updateScrollTop(@model.getFirstVisibleScreenRow() * @lineHeight)
restoreScrollLeftIfNeeded: ->
unless @scrollLeft?
@updateScrollLeft(@model.getFirstVisibleScreenColumn() * @baseCharacterWidth)
onDidChangeScrollTop: (callback) ->
@emitter.on 'did-change-scroll-top', callback

View File

@@ -54,13 +54,11 @@ GutterContainer = require './gutter-container'
# soft wraps and folds to ensure your code interacts with them correctly.
module.exports =
class TextEditor extends Model
callDisplayBufferCreatedHook: false
buffer: null
languageMode: null
cursors: null
selections: null
suppressSelectionMerging: false
updateBatchDepth: 0
selectionFlashDuration: 500
gutterContainer: null
@@ -90,7 +88,7 @@ class TextEditor extends Model
super
{
@softTabs, @scrollRow, @scrollColumn, initialLine, initialColumn, tabLength,
@softTabs, @firstVisibleScreenRow, @firstVisibleScreenColumn, initialLine, initialColumn, tabLength,
softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation,
@mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config,
@notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry,
@@ -106,6 +104,8 @@ class TextEditor extends Model
throw new Error("Must pass a project parameter when constructing TextEditors") unless @project?
throw new Error("Must pass an assert parameter when constructing TextEditors") unless @assert?
@firstVisibleScreenRow ?= 0
@firstVisibleScreenColumn ?= 0
@emitter = new Emitter
@disposables = new CompositeDisposable
@cursors = []
@@ -146,8 +146,8 @@ class TextEditor extends Model
deserializer: 'TextEditor'
id: @id
softTabs: @softTabs
scrollRow: @getScrollRow()
scrollColumn: @getScrollColumn()
firstVisibleScreenRow: @getFirstVisibleScreenRow()
firstVisibleScreenColumn: @getFirstVisibleScreenColumn()
displayBuffer: @displayBuffer.serialize()
selectionsMarkerLayerId: @selectionsMarkerLayer.id
@@ -453,6 +453,9 @@ class TextEditor extends Model
onDidChangeCharacterWidths: (callback) ->
@displayBuffer.onDidChangeCharacterWidths(callback)
onDidChangeFirstVisibleScreenRow: (callback, fromView) ->
@emitter.on 'did-change-first-visible-screen-row', callback
onDidChangeScrollTop: (callback) ->
Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.")
@@ -3130,14 +3133,6 @@ class TextEditor extends Model
@placeholderText = placeholderText
@emitter.emit 'did-change-placeholder-text', @placeholderText
getFirstVisibleScreenRow: ->
deprecate("This is now a view method. Call TextEditorElement::getFirstVisibleScreenRow instead.")
@viewRegistry.getView(this).getVisibleRowRange()[0]
getLastVisibleScreenRow: ->
Grim.deprecate("This is now a view method. Call TextEditorElement::getLastVisibleScreenRow instead.")
@viewRegistry.getView(this).getVisibleRowRange()[1]
pixelPositionForBufferPosition: (bufferPosition) ->
Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead")
@viewRegistry.getView(this).pixelPositionForBufferPosition(bufferPosition)
@@ -3192,11 +3187,40 @@ class TextEditor extends Model
Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
@displayBuffer.getWidth()
getScrollRow: -> @scrollRow
setScrollRow: (@scrollRow) ->
# Experimental: Scroll the editor such that the given screen row is at the
# top of the visible area.
setFirstVisibleScreenRow: (screenRow, fromView) ->
unless fromView
maxScreenRow = @getLineCount() - 1
unless @config.get('editor.scrollPastEnd')
height = @displayBuffer.getHeight()
lineHeightInPixels = @displayBuffer.getLineHeightInPixels()
if height? and lineHeightInPixels?
maxScreenRow -= Math.floor(height / lineHeightInPixels)
screenRow = Math.max(Math.min(screenRow, maxScreenRow), 0)
getScrollColumn: -> @scrollColumn
setScrollColumn: (@scrollColumn) ->
unless screenRow is @firstVisibleScreenRow
@firstVisibleScreenRow = screenRow
@emitter.emit 'did-change-first-visible-screen-row', screenRow unless fromView
getFirstVisibleScreenRow: -> @firstVisibleScreenRow
getLastVisibleScreenRow: ->
height = @displayBuffer.getHeight()
lineHeightInPixels = @displayBuffer.getLineHeightInPixels()
if height? and lineHeightInPixels?
Math.min(@firstVisibleScreenRow + Math.floor(height / lineHeightInPixels), @getLineCount() - 1)
else
null
getVisibleRowRange: ->
if lastVisibleScreenRow = @getLastVisibleScreenRow()
[@firstVisibleScreenRow, lastVisibleScreenRow]
else
null
setFirstVisibleScreenColumn: (@firstVisibleScreenColumn) ->
getFirstVisibleScreenColumn: -> @firstVisibleScreenColumn
getScrollTop: ->
Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.")
@@ -3253,11 +3277,6 @@ class TextEditor extends Model
@viewRegistry.getView(this).getMaxScrollTop()
getVisibleRowRange: ->
Grim.deprecate("This is now a view method. Call TextEditorElement::getVisibleRowRange instead.")
@viewRegistry.getView(this).getVisibleRowRange()
intersectsVisibleRowRange: (startRow, endRow) ->
Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.")