diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index ac78d9947..e7de63964 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -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) diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 4c80659ec..2334b1318 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -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 "" 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) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 71b13a498..44b7569f8 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -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()