mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
Move vertical scroll state to root of presenter state object
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
@@ -33,6 +33,31 @@ describe "TextEditorPresenter", ->
|
||||
# These `describe` and `it` blocks mirror the structure of the ::state object.
|
||||
# Please maintain this structure when adding specs for new state fields.
|
||||
describe "::state", ->
|
||||
describe ".scrollHeight", ->
|
||||
it "is initialized based on the lineHeight, the number of lines, and the clientHeight", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
|
||||
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, clientHeight: 500)
|
||||
expect(presenter.state.scrollHeight).toBe 500
|
||||
|
||||
it "updates when the ::lineHeight changes", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
|
||||
expectStateUpdate presenter, -> presenter.setLineHeight(20)
|
||||
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 20
|
||||
|
||||
it "updates when the line count changes", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
|
||||
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
|
||||
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
|
||||
|
||||
describe ".scrollTop", ->
|
||||
it "tracks the value of ::scrollTop", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
|
||||
expect(presenter.state.scrollTop).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(50)
|
||||
expect(presenter.state.scrollTop).toBe 50
|
||||
|
||||
describe ".content", ->
|
||||
describe ".scrollWidth", ->
|
||||
it "is initialized as the max of the clientWidth and the width of the longest line", ->
|
||||
@@ -79,28 +104,6 @@ describe "TextEditorPresenter", ->
|
||||
expectStateUpdate presenter, -> editor.setSoftWrapped(false)
|
||||
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
|
||||
|
||||
describe ".scrollHeight", ->
|
||||
it "is initialized based on the lineHeight and the number of lines", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
|
||||
|
||||
it "updates when the ::lineHeight changes", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expectStateUpdate presenter, -> presenter.setLineHeight(20)
|
||||
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 20
|
||||
|
||||
it "updates when the line count changes", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
|
||||
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
|
||||
|
||||
describe ".scrollTop", ->
|
||||
it "tracks the value of ::scrollTop", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
expect(presenter.state.content.scrollTop).toBe 10
|
||||
expectStateUpdate presenter, -> presenter.setScrollTop(50)
|
||||
expect(presenter.state.content.scrollTop).toBe 50
|
||||
|
||||
describe ".scrollLeft", ->
|
||||
it "tracks the value of ::scrollLeft", ->
|
||||
presenter = new TextEditorPresenter(model: editor, scrollLeft: 10, lineHeight: 10, lineOverdrawMargin: 1)
|
||||
|
||||
@@ -23,9 +23,10 @@ LinesComponent = React.createClass
|
||||
{editor, presenter, overlayDecorations, highlightDecorations, placeholderText, backgroundColor} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount, cursorPixelRects} = @props
|
||||
|
||||
@oldState ?= {lines: {}}
|
||||
@newState = presenter.state.content
|
||||
{scrollWidth, scrollHeight} = @newState
|
||||
@oldState ?= {content: {lines: {}}}
|
||||
@newState = presenter.state
|
||||
{scrollHeight} = @newState
|
||||
{scrollWidth} = @newState.content
|
||||
|
||||
style =
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
@@ -40,7 +41,8 @@ LinesComponent = React.createClass
|
||||
HighlightsComponent {presenter, performedInitialMeasurement}
|
||||
|
||||
getTransform: ->
|
||||
{scrollTop, scrollLeft} = @newState
|
||||
{scrollTop} = @newState
|
||||
{scrollLeft} = @newState.content
|
||||
{useHardwareAcceleration} = @props
|
||||
|
||||
if useHardwareAcceleration
|
||||
@@ -72,41 +74,41 @@ LinesComponent = React.createClass
|
||||
{visible, scrollingVertically, performedInitialMeasurement} = @props
|
||||
return unless performedInitialMeasurement
|
||||
|
||||
@removeLineNodes() unless @oldState?.indentGuidesVisible is @newState?.indentGuidesVisible
|
||||
@removeLineNodes() unless @oldState?.content.indentGuidesVisible is @newState?.content.indentGuidesVisible
|
||||
@updateLineNodes()
|
||||
@measureCharactersInNewLines() if visible and not scrollingVertically
|
||||
|
||||
@overlayManager?.render(@props)
|
||||
|
||||
@oldState.indentGuidesVisible = @newState.indentGuidesVisible
|
||||
@oldState.scrollWidth = @newState.scrollWidth
|
||||
@oldState.content.indentGuidesVisible = @newState.content.indentGuidesVisible
|
||||
@oldState.content.scrollWidth = @newState.content.scrollWidth
|
||||
|
||||
clearScreenRowCaches: ->
|
||||
@screenRowsByLineId = {}
|
||||
@lineIdsByScreenRow = {}
|
||||
|
||||
removeLineNodes: ->
|
||||
@removeLineNode(id) for id of @oldState.lines
|
||||
@removeLineNode(id) for id of @oldState.content.lines
|
||||
|
||||
removeLineNode: (id) ->
|
||||
@lineNodesByLineId[id].remove()
|
||||
delete @lineNodesByLineId[id]
|
||||
delete @lineIdsByScreenRow[@screenRowsByLineId[id]]
|
||||
delete @screenRowsByLineId[id]
|
||||
delete @oldState.lines[id]
|
||||
delete @oldState.content.lines[id]
|
||||
|
||||
updateLineNodes: ->
|
||||
{presenter, mouseWheelScreenRow} = @props
|
||||
|
||||
for id of @oldState.lines
|
||||
unless @newState.lines.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
|
||||
for id of @oldState.content.lines
|
||||
unless @newState.content.lines.hasOwnProperty(id) or mouseWheelScreenRow is @screenRowsByLineId[id]
|
||||
@removeLineNode(id)
|
||||
|
||||
newLineIds = null
|
||||
newLinesHTML = null
|
||||
|
||||
for id, lineState of @newState.lines
|
||||
if @oldState.lines.hasOwnProperty(id)
|
||||
for id, lineState of @newState.content.lines
|
||||
if @oldState.content.lines.hasOwnProperty(id)
|
||||
@updateLineNode(id)
|
||||
else
|
||||
newLineIds ?= []
|
||||
@@ -115,7 +117,7 @@ LinesComponent = React.createClass
|
||||
newLinesHTML += @buildLineHTML(id)
|
||||
@screenRowsByLineId[id] = lineState.screenRow
|
||||
@lineIdsByScreenRow[lineState.screenRow] = id
|
||||
@oldState.lines[id] = _.clone(lineState)
|
||||
@oldState.content.lines[id] = _.clone(lineState)
|
||||
|
||||
return unless newLineIds?
|
||||
|
||||
@@ -129,8 +131,8 @@ LinesComponent = React.createClass
|
||||
|
||||
buildLineHTML: (id) ->
|
||||
{presenter} = @props
|
||||
{scrollWidth} = @newState
|
||||
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id]
|
||||
{scrollWidth} = @newState.content
|
||||
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.content.lines[id]
|
||||
|
||||
classes = ''
|
||||
if decorationClasses?
|
||||
@@ -150,8 +152,8 @@ LinesComponent = React.createClass
|
||||
lineHTML
|
||||
|
||||
buildEmptyLineInnerHTML: (id) ->
|
||||
{indentGuidesVisible} = @newState
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id]
|
||||
{indentGuidesVisible} = @newState.content
|
||||
{indentLevel, tabLength, endOfLineInvisibles} = @newState.content.lines[id]
|
||||
|
||||
if indentGuidesVisible and indentLevel > 0
|
||||
invisibleIndex = 0
|
||||
@@ -174,8 +176,8 @@ LinesComponent = React.createClass
|
||||
|
||||
buildLineInnerHTML: (id) ->
|
||||
{editor} = @props
|
||||
{indentGuidesVisible} = @newState
|
||||
{tokens, text} = @newState.lines[id]
|
||||
{indentGuidesVisible} = @newState.content
|
||||
{tokens, text} = @newState.content.lines[id]
|
||||
innerHTML = ""
|
||||
|
||||
scopeStack = []
|
||||
@@ -191,7 +193,7 @@ LinesComponent = React.createClass
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: (id) ->
|
||||
{endOfLineInvisibles} = @newState.lines[id]
|
||||
{endOfLineInvisibles} = @newState.content.lines[id]
|
||||
|
||||
html = ''
|
||||
if endOfLineInvisibles?
|
||||
@@ -225,13 +227,13 @@ LinesComponent = React.createClass
|
||||
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
|
||||
|
||||
updateLineNode: (id) ->
|
||||
{scrollWidth} = @newState
|
||||
{screenRow, top} = @newState.lines[id]
|
||||
{scrollWidth} = @newState.content
|
||||
{screenRow, top} = @newState.content.lines[id]
|
||||
|
||||
lineNode = @lineNodesByLineId[id]
|
||||
|
||||
newDecorationClasses = @newState.lines[id].decorationClasses
|
||||
oldDecorationClasses = @oldState.lines[id].decorationClasses
|
||||
newDecorationClasses = @newState.content.lines[id].decorationClasses
|
||||
oldDecorationClasses = @oldState.content.lines[id].decorationClasses
|
||||
|
||||
if oldDecorationClasses?
|
||||
for decorationClass in oldDecorationClasses
|
||||
@@ -276,7 +278,7 @@ LinesComponent = React.createClass
|
||||
node = @getDOMNode()
|
||||
|
||||
editor.batchCharacterMeasurement =>
|
||||
for id, lineState of @oldState.lines
|
||||
for id, lineState of @oldState.content.lines
|
||||
unless @measuredLines.has(id)
|
||||
lineNode = @lineNodesByLineId[id]
|
||||
@measureCharactersInLine(lineState, lineNode)
|
||||
|
||||
@@ -47,16 +47,19 @@ class TextEditorPresenter
|
||||
@updateState()
|
||||
|
||||
updateState: ->
|
||||
@updateVerticalScrollState()
|
||||
@updateContentState()
|
||||
@updateLinesState()
|
||||
@updateCursorsState()
|
||||
@updateHighlightsState()
|
||||
@updateLineNumbersState()
|
||||
|
||||
updateVerticalScrollState: ->
|
||||
@state.scrollHeight = @computeScrollHeight()
|
||||
@state.scrollTop = @getScrollTop()
|
||||
|
||||
updateContentState: ->
|
||||
@state.content.scrollWidth = @computeScrollWidth()
|
||||
@state.content.scrollHeight = @computeScrollHeight()
|
||||
@state.content.scrollTop = @getScrollTop()
|
||||
@state.content.scrollLeft = @getScrollLeft()
|
||||
@state.content.indentGuidesVisible = atom.config.get('editor.showIndentGuide', scope: @model.getRootScopeDescriptor())
|
||||
@emitter.emit 'did-update-state'
|
||||
@@ -230,7 +233,7 @@ class TextEditorPresenter
|
||||
Math.max(contentWidth, @getClientWidth())
|
||||
|
||||
computeScrollHeight: ->
|
||||
@getLineHeight() * @model.getScreenLineCount()
|
||||
Math.max(@getLineHeight() * @model.getScreenLineCount(), @getClientHeight())
|
||||
|
||||
lineDecorationClassesForRow: (row) ->
|
||||
return null if @model.isMini()
|
||||
@@ -277,7 +280,7 @@ class TextEditorPresenter
|
||||
getCursorBlinkResumeDelay: -> @cursorBlinkResumeDelay
|
||||
|
||||
setScrollTop: (@scrollTop) ->
|
||||
@updateContentState()
|
||||
@updateVerticalScrollState()
|
||||
@updateLinesState()
|
||||
@updateCursorsState()
|
||||
@updateHighlightsState()
|
||||
@@ -306,7 +309,7 @@ class TextEditorPresenter
|
||||
getClientWidth: -> @clientWidth
|
||||
|
||||
setLineHeight: (@lineHeight) ->
|
||||
@updateContentState()
|
||||
@updateVerticalScrollState()
|
||||
@updateLinesState()
|
||||
@updateCursorsState()
|
||||
@updateHighlightsState()
|
||||
|
||||
Reference in New Issue
Block a user