diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index cc7eba628..ce319ead0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -33,50 +33,6 @@ 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 height", -> - 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, height: 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 - - it "updates when ::height changes", -> - presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) - expectStateUpdate presenter, -> presenter.setHeight(500) - expect(presenter.state.scrollHeight).toBe 500 - - 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 ".scrollingVertically", -> - it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", -> - presenter = new TextEditorPresenter(model: editor, scrollTop: 10, stoppedScrollingDelay: 200) - expect(presenter.state.scrollingVertically).toBe false - expectStateUpdate presenter, -> presenter.setScrollTop(0) - expect(presenter.state.scrollingVertically).toBe true - advanceClock(100) - expect(presenter.state.scrollingVertically).toBe true - presenter.setScrollTop(10) - advanceClock(100) - expect(presenter.state.scrollingVertically).toBe true - expectStateUpdate presenter, -> advanceClock(100) - expect(presenter.state.scrollingVertically).toBe false - describe ".horizontalScrollbar", -> describe ".visible", -> it "is true if the scrollWidth exceeds the computed client width", -> @@ -127,6 +83,58 @@ describe "TextEditorPresenter", -> presenter.setHeight((editor.getLineCount() * 10) - 1) expect(state.horizontalScrollbar.right).toBe 10 + describe ".scrollWidth", -> + it "is initialized as the max of the ::contentFrameWidth and the width of the longest line", -> + maxLineLength = editor.getMaxScreenLineLength() + + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + + it "updates when the ::contentFrameWidth changes", -> + maxLineLength = editor.getMaxScreenLineLength() + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10) + + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + + it "updates when the ::baseCharacterWidth changes", -> + maxLineLength = editor.getMaxScreenLineLength() + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10) + + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(15) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 15 * maxLineLength + 1 + + it "updates when the scoped character widths change", -> + waitsForPromise -> atom.packages.activatePackage('language-javascript') + + runs -> + maxLineLength = editor.getMaxScreenLineLength() + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10) + + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expectStateUpdate presenter, -> presenter.setScopedCharWidth(['source.js', 'support.function.js'], 'p', 20) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide + + it "updates when ::softWrapped changes on the editor", -> + presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expectStateUpdate presenter, -> editor.setSoftWrapped(true) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + expectStateUpdate presenter, -> editor.setSoftWrapped(false) + expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + + describe ".scrollLeft", -> + it "tracks the value of ::scrollLeft", -> + presenter = new TextEditorPresenter(model: editor, scrollLeft: 10, lineHeight: 10, lineOverdrawMargin: 1) + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollLeft(50) + expect(presenter.state.horizontalScrollbar.scrollLeft).toBe 50 + describe ".verticalScrollbar", -> describe ".visible", -> it "is true if the scrollHeight exceeds the computed client height", -> @@ -177,7 +185,74 @@ describe "TextEditorPresenter", -> presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) expect(state.verticalScrollbar.bottom).toBe 10 + describe ".scrollHeight", -> + it "is initialized based on the lineHeight, the number of lines, and the height", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expect(presenter.state.verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500) + expect(presenter.state.verticalScrollbar.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.verticalScrollbar.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.verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + + it "updates when ::height changes", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expectStateUpdate presenter, -> presenter.setHeight(500) + expect(presenter.state.verticalScrollbar.scrollHeight).toBe 500 + + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10) + expect(presenter.state.verticalScrollbar.scrollTop).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollTop(50) + expect(presenter.state.verticalScrollbar.scrollTop).toBe 50 + describe ".content", -> + describe ".scrollingVertically", -> + it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 10, stoppedScrollingDelay: 200) + expect(presenter.state.content.scrollingVertically).toBe false + expectStateUpdate presenter, -> presenter.setScrollTop(0) + expect(presenter.state.content.scrollingVertically).toBe true + advanceClock(100) + expect(presenter.state.content.scrollingVertically).toBe true + presenter.setScrollTop(10) + advanceClock(100) + expect(presenter.state.content.scrollingVertically).toBe true + expectStateUpdate presenter, -> advanceClock(100) + expect(presenter.state.content.scrollingVertically).toBe false + + describe ".scrollHeight", -> + it "is initialized based on the lineHeight, the number of lines, and the height", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10 + + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500) + expect(presenter.state.content.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.content.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.content.scrollHeight).toBe editor.getScreenLineCount() * 10 + + it "updates when ::height changes", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expectStateUpdate presenter, -> presenter.setHeight(500) + expect(presenter.state.content.scrollHeight).toBe 500 + describe ".scrollWidth", -> it "is initialized as the max of the ::contentFrameWidth and the width of the longest line", -> maxLineLength = editor.getMaxScreenLineLength() @@ -223,6 +298,13 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> editor.setSoftWrapped(false) expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10) + 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) @@ -1236,6 +1318,36 @@ describe "TextEditorPresenter", -> expect(presenter.state.content.overlays).not.toEqual({}) describe ".gutter", -> + describe ".scrollHeight", -> + it "is initialized based on the lineHeight, the number of lines, and the height", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expect(presenter.state.gutter.scrollHeight).toBe editor.getScreenLineCount() * 10 + + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500) + expect(presenter.state.gutter.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.gutter.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.gutter.scrollHeight).toBe editor.getScreenLineCount() * 10 + + it "updates when ::height changes", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10) + expectStateUpdate presenter, -> presenter.setHeight(500) + expect(presenter.state.gutter.scrollHeight).toBe 500 + + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10) + expect(presenter.state.gutter.scrollTop).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollTop(50) + expect(presenter.state.gutter.scrollTop).toBe 50 + describe ".backgroundColor", -> it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> presenter = new TextEditorPresenter(model: editor, backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 26469065b..5b6af4f6a 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -19,16 +19,20 @@ GutterComponent = React.createClass render: -> {presenter} = @props + @newState = presenter.state.gutter + @oldState ?= {lineNumbers: {}} + + {scrollHeight, backgroundColor} = @newState div className: 'gutter', div className: 'line-numbers', ref: 'lineNumbers', style: - height: presenter.state.scrollHeight + height: scrollHeight WebkitTransform: @getTransform() if presenter.hasRequiredMeasurements() - backgroundColor: presenter.state.gutter.backgroundColor + backgroundColor: backgroundColor getTransform: -> - {presenter, useHardwareAcceleration} = @props - {scrollTop} = presenter.state + {useHardwareAcceleration} = @props + {scrollTop} = @newState if useHardwareAcceleration "translate3d(0px, #{-scrollTop}px, 0px)" @@ -39,7 +43,7 @@ GutterComponent = React.createClass @lineNumberNodesById = {} componentDidMount: -> - {@maxLineNumberDigits} = @props.presenter.state.gutter + {@maxLineNumberDigits} = @newState @appendDummyLineNumber() @updateLineNumbers() @@ -48,7 +52,7 @@ GutterComponent = React.createClass node.addEventListener 'mousedown', @onMouseDown componentDidUpdate: (oldProps) -> - {maxLineNumberDigits} = @props.presenter.state.gutter + {maxLineNumberDigits} = @newState unless maxLineNumberDigits is @maxLineNumberDigits @maxLineNumberDigits = maxLineNumberDigits @updateDummyLineNumber() @@ -69,13 +73,10 @@ GutterComponent = React.createClass @dummyLineNumberNode.innerHTML = @buildLineNumberInnerHTML(0, false) updateLineNumbers: -> - {presenter} = @props - @oldState ?= {lineNumbers: {}} - newState = presenter.state.gutter newLineNumberIds = null newLineNumbersHTML = null - for id, lineNumberState of newState.lineNumbers + for id, lineNumberState of @newState.lineNumbers if @oldState.lineNumbers.hasOwnProperty(id) @updateLineNumberNode(id, lineNumberState) else @@ -96,7 +97,7 @@ GutterComponent = React.createClass node.appendChild(lineNumberNode) for id, lineNumberState of @oldState.lineNumbers - unless newState.lineNumbers.hasOwnProperty(id) + unless @newState.lineNumbers.hasOwnProperty(id) @lineNumberNodesById[id].remove() delete @lineNumberNodesById[id] delete @oldState.lineNumbers[id] @@ -113,7 +114,7 @@ GutterComponent = React.createClass "
#{innerHTML}
" buildLineNumberInnerHTML: (bufferRow, softWrapped) -> - {maxLineNumberDigits} = @props.presenter.state.gutter + {maxLineNumberDigits} = @newState if softWrapped lineNumber = "•" diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 6e1898cdd..bd9589f72 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -18,11 +18,10 @@ LinesComponent = React.createClass render: -> {editor, presenter} = @props - @oldState ?= {content: {lines: {}}} - @newState = presenter.state + @oldState ?= {lines: {}} + @newState = presenter.state.content - {scrollHeight} = @newState - {scrollWidth, backgroundColor, placeholderText} = @newState.content + {scrollHeight, scrollWidth, backgroundColor, placeholderText} = @newState style = height: scrollHeight @@ -36,8 +35,7 @@ LinesComponent = React.createClass HighlightsComponent {presenter} getTransform: -> - {scrollTop} = @newState - {scrollLeft} = @newState.content + {scrollTop, scrollLeft} = @newState {useHardwareAcceleration} = @props if useHardwareAcceleration @@ -68,41 +66,41 @@ LinesComponent = React.createClass componentDidUpdate: -> {visible, presenter} = @props - @removeLineNodes() unless @oldState?.content.indentGuidesVisible is @newState?.content.indentGuidesVisible + @removeLineNodes() unless @oldState?.indentGuidesVisible is @newState?.indentGuidesVisible @updateLineNodes() @measureCharactersInNewLines() if visible and not presenter.state.scrollingVertically @overlayManager?.render(@props) - @oldState.content.indentGuidesVisible = @newState.content.indentGuidesVisible - @oldState.content.scrollWidth = @newState.content.scrollWidth + @oldState.indentGuidesVisible = @newState.indentGuidesVisible + @oldState.scrollWidth = @newState.scrollWidth clearScreenRowCaches: -> @screenRowsByLineId = {} @lineIdsByScreenRow = {} removeLineNodes: -> - @removeLineNode(id) for id of @oldState.content.lines + @removeLineNode(id) for id of @oldState.lines removeLineNode: (id) -> @lineNodesByLineId[id].remove() delete @lineNodesByLineId[id] delete @lineIdsByScreenRow[@screenRowsByLineId[id]] delete @screenRowsByLineId[id] - delete @oldState.content.lines[id] + delete @oldState.lines[id] updateLineNodes: -> {presenter} = @props - for id of @oldState.content.lines - unless @newState.content.lines.hasOwnProperty(id) + for id of @oldState.lines + unless @newState.lines.hasOwnProperty(id) @removeLineNode(id) newLineIds = null newLinesHTML = null - for id, lineState of @newState.content.lines - if @oldState.content.lines.hasOwnProperty(id) + for id, lineState of @newState.lines + if @oldState.lines.hasOwnProperty(id) @updateLineNode(id) else newLineIds ?= [] @@ -111,7 +109,7 @@ LinesComponent = React.createClass newLinesHTML += @buildLineHTML(id) @screenRowsByLineId[id] = lineState.screenRow @lineIdsByScreenRow[lineState.screenRow] = id - @oldState.content.lines[id] = _.clone(lineState) + @oldState.lines[id] = _.clone(lineState) return unless newLineIds? @@ -125,8 +123,8 @@ LinesComponent = React.createClass buildLineHTML: (id) -> {presenter} = @props - {scrollWidth} = @newState.content - {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.content.lines[id] + {scrollWidth} = @newState + {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id] classes = '' if decorationClasses? @@ -146,8 +144,8 @@ LinesComponent = React.createClass lineHTML buildEmptyLineInnerHTML: (id) -> - {indentGuidesVisible} = @newState.content - {indentLevel, tabLength, endOfLineInvisibles} = @newState.content.lines[id] + {indentGuidesVisible} = @newState + {indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id] if indentGuidesVisible and indentLevel > 0 invisibleIndex = 0 @@ -170,8 +168,8 @@ LinesComponent = React.createClass buildLineInnerHTML: (id) -> {editor} = @props - {indentGuidesVisible} = @newState.content - {tokens, text} = @newState.content.lines[id] + {indentGuidesVisible} = @newState + {tokens, text} = @newState.lines[id] innerHTML = "" scopeStack = [] @@ -187,7 +185,7 @@ LinesComponent = React.createClass innerHTML buildEndOfLineHTML: (id) -> - {endOfLineInvisibles} = @newState.content.lines[id] + {endOfLineInvisibles} = @newState.lines[id] html = '' if endOfLineInvisibles? @@ -221,13 +219,13 @@ LinesComponent = React.createClass "" updateLineNode: (id) -> - {scrollWidth} = @newState.content - {screenRow, top} = @newState.content.lines[id] + {scrollWidth} = @newState + {screenRow, top} = @newState.lines[id] lineNode = @lineNodesByLineId[id] - newDecorationClasses = @newState.content.lines[id].decorationClasses - oldDecorationClasses = @oldState.content.lines[id].decorationClasses + newDecorationClasses = @newState.lines[id].decorationClasses + oldDecorationClasses = @oldState.lines[id].decorationClasses if oldDecorationClasses? for decorationClass in oldDecorationClasses @@ -272,7 +270,7 @@ LinesComponent = React.createClass node = @getDOMNode() editor.batchCharacterMeasurement => - for id, lineState of @oldState.content.lines + for id, lineState of @oldState.lines unless @measuredLines.has(id) lineNode = @lineNodesByLineId[id] @measureCharactersInLine(lineState, lineNode) diff --git a/src/overlay-manager.coffee b/src/overlay-manager.coffee index 3fc86d403..b61554e03 100644 --- a/src/overlay-manager.coffee +++ b/src/overlay-manager.coffee @@ -27,8 +27,7 @@ class OverlayManager itemHeight = item.offsetHeight - {scrollTop} = presenter.state - {scrollLeft} = presenter.state.content + {scrollTop, scrollLeft} = presenter.state.content left = pixelPosition.left if left + itemWidth - scrollLeft > presenter.getContentFrameWidth() and left - itemWidth >= scrollLeft diff --git a/src/scrollbar-component.coffee b/src/scrollbar-component.coffee index 704cf6e63..eaf64b8bc 100644 --- a/src/scrollbar-component.coffee +++ b/src/scrollbar-component.coffee @@ -11,29 +11,29 @@ ScrollbarComponent = React.createClass switch orientation when 'vertical' - state = presenter.state.verticalScrollbar + @newState = presenter.state.verticalScrollbar when 'horizontal' - state = presenter.state.horizontalScrollbar + @newState = presenter.state.horizontalScrollbar style = {} - style.display = 'none' unless state.visible + style.display = 'none' unless @newState.visible style.transform = 'translateZ(0)' if useHardwareAcceleration # See atom/atom#3559 switch orientation when 'vertical' - style.width = state.width - style.bottom = state.bottom + style.width = @newState.width + style.bottom = @newState.bottom when 'horizontal' style.left = 0 - style.right = state.right - style.height = state.height + style.right = @newState.right + style.height = @newState.height div {className, style}, switch orientation when 'vertical' - div className: 'scrollbar-content', style: {height: presenter.state.scrollHeight} + div className: 'scrollbar-content', style: {height: @newState.scrollHeight} when 'horizontal' - div className: 'scrollbar-content', style: {width: presenter.state.content.scrollWidth} + div className: 'scrollbar-content', style: {width: @newState.scrollWidth} componentDidMount: -> {orientation} = @props @@ -47,14 +47,14 @@ ScrollbarComponent = React.createClass @getDOMNode().removeEventListener 'scroll', @onScroll componentDidUpdate: -> - {orientation, presenter} = @props + {orientation} = @props node = @getDOMNode() switch orientation when 'vertical' - node.scrollTop = presenter.state.scrollTop + node.scrollTop = @newState.scrollTop when 'horizontal' - node.scrollLeft = presenter.state.content.scrollLeft + node.scrollLeft = @newState.scrollLeft onScroll: -> {orientation, onScroll} = @props diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 30a12426a..ea9c4b2f9 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -34,7 +34,6 @@ TextEditorComponent = React.createClass scrollSensitivity: 0.4 heightAndWidthMeasurementRequested: false inputEnabled: true - scopedCharacterWidthsChangeCount: null domPollingInterval: 100 domPollingIntervalId: null domPollingPaused: false @@ -56,7 +55,7 @@ TextEditorComponent = React.createClass hiddenInputStyle = @getHiddenInputPosition() hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration - style.height = @presenter.state.scrollHeight if @autoHeight + style.height = @presenter.state.content.scrollHeight if @autoHeight if useShadowDOM className = 'editor-contents--private' @@ -233,7 +232,6 @@ TextEditorComponent = React.createClass @subscribe editor.observeGrammar(@onGrammarChanged) @subscribe editor.observeCursors(@onCursorAdded) @subscribe editor.observeSelections(@onSelectionAdded) - @subscribe editor.onDidChangeCharacterWidths(@onCharacterWidthsChanged) @subscribe editor.$scrollTop.changes, @onScrollTopChanged @subscribe editor.$scrollLeft.changes, @onScrollLeftChanged @subscribe editor.$verticalScrollbarWidth.changes, @requestUpdate @@ -579,9 +577,6 @@ TextEditorComponent = React.createClass @cursorMoved = true @requestUpdate() - onCharacterWidthsChanged: (@scopedCharacterWidthsChangeCount) -> - @requestUpdate() - handleDragUntilMouseUp: (event, dragHandler) -> {editor} = @props dragging = false diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 7d2326a64..abe430aac 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -51,10 +51,10 @@ class TextEditorPresenter buildState: -> @state = - scrollingVertically: false horizontalScrollbar: {} verticalScrollbar: {} content: + scrollingVertically: false blinkCursorsOff: false lines: {} highlights: {} @@ -65,6 +65,7 @@ class TextEditorPresenter updateState: -> @updateVerticalScrollState() + @updateHorizontalScrollState() @updateScrollbarsState() @updateContentState() @updateLinesState() @@ -75,8 +76,28 @@ class TextEditorPresenter @updateLineNumbersState() updateVerticalScrollState: -> - @state.scrollHeight = @computeScrollHeight() - @state.scrollTop = @getScrollTop() + scrollHeight = @computeScrollHeight() + @state.content.scrollHeight = scrollHeight + @state.gutter.scrollHeight = scrollHeight + @state.verticalScrollbar.scrollHeight = scrollHeight + + scrollTop = @getScrollTop() + @state.content.scrollTop = scrollTop + @state.gutter.scrollTop = scrollTop + @state.verticalScrollbar.scrollTop = scrollTop + + @emitter.emit 'did-update-state' + + updateHorizontalScrollState: -> + scrollWidth = @computeScrollWidth() + @state.content.scrollWidth = scrollWidth + @state.horizontalScrollbar.scrollWidth = scrollWidth + + scrollLeft = @getScrollLeft() + @state.content.scrollLeft = @getScrollLeft() + @state.horizontalScrollbar.scrollLeft = @getScrollLeft() + + @emitter.emit 'did-update-state' updateScrollbarsState: -> contentWidth = @computeContentWidth() @@ -406,11 +427,11 @@ class TextEditorPresenter clearTimeout(@stoppedScrollingTimeoutId) @stoppedScrollingTimeoutId = null @stoppedScrollingTimeoutId = setTimeout(@didStopScrolling.bind(this), @stoppedScrollingDelay) - @state.scrollingVertically = true + @state.content.scrollingVertically = true @emitter.emit 'did-update-state' didStopScrolling: -> - @state.scrollingVertically = false + @state.content.scrollingVertically = false if @getMouseWheelScreenRow()? @mouseWheelScreenRow = null @updateLinesState() @@ -421,7 +442,7 @@ class TextEditorPresenter getScrollTop: -> @scrollTop setScrollLeft: (@scrollLeft) -> - @updateContentState() + @updateHorizontalScrollState() getScrollLeft: -> @scrollLeft @@ -447,6 +468,7 @@ class TextEditorPresenter @height ? @model.getScreenLineCount() * @getLineHeight() setContentFrameWidth: (@contentFrameWidth) -> + @updateHorizontalScrollState() @updateScrollbarsState() @updateContentState() @updateLinesState() @@ -511,6 +533,7 @@ class TextEditorPresenter @characterWidthsChanged() unless @batchingCharacterMeasurement characterWidthsChanged: -> + @updateHorizontalScrollState() @updateContentState() @updateLinesState() @updateCursorsState()