From 255864fc9d2620aec693424a6b827d231582c41b Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Thu, 10 Dec 2015 13:52:10 +0100 Subject: [PATCH 1/3] :arrow_up: language-go@0.41.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0b4904ca..e61892fc3 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "language-css": "0.36.0", "language-gfm": "0.82.0", "language-git": "0.11.0", - "language-go": "0.40.0", + "language-go": "0.41.0", "language-html": "0.43.1", "language-hyperlink": "0.16.0", "language-java": "0.17.0", From 50dc9b6bb4de32f3a3b2ed2e5e83e64fc1f3422d Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 11 Dec 2015 06:17:15 +0900 Subject: [PATCH 2/3] :arrow_up: one-dark/light-ui@v1.1.9 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e61892fc3..36ffb2dcb 100644 --- a/package.json +++ b/package.json @@ -64,10 +64,10 @@ "atom-light-ui": "0.43.0", "base16-tomorrow-dark-theme": "1.0.0", "base16-tomorrow-light-theme": "1.0.0", - "one-dark-ui": "1.1.8", + "one-dark-ui": "1.1.9", "one-dark-syntax": "1.1.1", "one-light-syntax": "1.1.1", - "one-light-ui": "1.1.8", + "one-light-ui": "1.1.9", "solarized-dark-syntax": "0.39.0", "solarized-light-syntax": "0.23.0", "about": "1.1.0", From 85c61395798240c80a6816d8abee54aa7519af76 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 4 Dec 2015 19:02:24 -0700 Subject: [PATCH 3/3] =?UTF-8?q?Don=E2=80=99t=20force=20DOM=20updates=20in?= =?UTF-8?q?=20LinesYardstick?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, determine the need for a DOM update in the component before measuring with the lines yardstick, and break `updateSync` into two explicit pre- and post-measurement phases. --- spec/fake-lines-yardstick.coffee | 23 +- spec/lines-yardstick-spec.coffee | 42 +-- spec/text-editor-presenter-spec.coffee | 492 +++++++++++++------------ src/lines-yardstick.coffee | 47 +-- src/text-editor-component.coffee | 49 ++- src/text-editor-presenter.coffee | 30 +- 6 files changed, 323 insertions(+), 360 deletions(-) diff --git a/spec/fake-lines-yardstick.coffee b/spec/fake-lines-yardstick.coffee index 1872b8c65..da5f8327e 100644 --- a/spec/fake-lines-yardstick.coffee +++ b/spec/fake-lines-yardstick.coffee @@ -2,13 +2,9 @@ module.exports = class FakeLinesYardstick - constructor: (@model, @presenter) -> + constructor: (@model) -> @characterWidthsByScope = {} - prepareScreenRowsForMeasurement: -> - @presenter.getPreMeasurementState() - @screenRows = new Set(@presenter.getScreenRows()) - getScopedCharacterWidth: (scopeNames, char) -> @getScopedCharacterWidths(scopeNames)[char] @@ -35,8 +31,6 @@ class FakeLinesYardstick left = 0 column = 0 - return {top, left: 0} unless @screenRows.has(screenPosition.row) - iterator = @model.tokenizedLineForScreenRow(targetRow).getTokenIterator() while iterator.next() characterWidths = @getScopedCharacterWidths(iterator.getScopes()) @@ -59,18 +53,3 @@ class FakeLinesYardstick column += charLength {top, left} - - pixelRectForScreenRange: (screenRange) -> - lineHeight = @model.getLineHeightInPixels() - - if screenRange.end.row > screenRange.start.row - top = @pixelPositionForScreenPosition(screenRange.start).top - left = 0 - height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight - width = @presenter.getScrollWidth() - else - {top, left} = @pixelPositionForScreenPosition(screenRange.start, false) - height = lineHeight - width = @pixelPositionForScreenPosition(screenRange.end, false).left - left - - {top, left, width, height} diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee index ae85a0e9d..74f5fca6a 100644 --- a/spec/lines-yardstick-spec.coffee +++ b/spec/lines-yardstick-spec.coffee @@ -2,7 +2,7 @@ LinesYardstick = require "../src/lines-yardstick" {toArray} = require 'underscore-plus' describe "LinesYardstick", -> - [editor, mockPresenter, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = [] + [editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = [] beforeEach -> waitsForPromise -> @@ -31,22 +31,10 @@ describe "LinesYardstick", -> createdLineNodes.push(lineNode) lineNode - mockPresenter = - setScreenRowsToMeasure: (screenRows) -> screenRowsToMeasure = screenRows - clearScreenRowsToMeasure: -> setScreenRowsToMeasure = [] - getPreMeasurementState: -> - state = {} - for screenRow in screenRowsToMeasure - tokenizedLine = editor.tokenizedLineForScreenRow(screenRow) - state[tokenizedLine.id] = screenRow - state - mockLineNodesProvider = - updateSync: (state) -> availableScreenRows = state lineNodeForLineIdAndScreenRow: (lineId, screenRow) -> - return if availableScreenRows[lineId] isnt screenRow - buildLineNode(screenRow) + textNodesForLineIdAndScreenRow: (lineId, screenRow) -> lineNode = @lineNodeForLineIdAndScreenRow(lineId, screenRow) iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT) @@ -56,7 +44,7 @@ describe "LinesYardstick", -> textNodes editor.setLineHeightInPixels(14) - linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider, atom.grammars) + linesYardstick = new LinesYardstick(editor, mockLineNodesProvider, atom.grammars) afterEach -> lineNode.remove() for lineNode in createdLineNodes @@ -153,18 +141,6 @@ describe "LinesYardstick", -> expect(linesYardstick.pixelPositionForScreenPosition([0, 36]).left).toBe 237.5 expect(linesYardstick.pixelPositionForScreenPosition([0, 37]).left).toBe 244.09375 - it "doesn't measure invisible lines if it is explicitly told so", -> - atom.styles.addStyleSheet """ - * { - font-size: 12px; - font-family: monospace; - } - """ - - expect(linesYardstick.pixelPositionForScreenPosition([0, 0], true, true)).toEqual({left: 0, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 1], true, true)).toEqual({left: 0, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 5], true, true)).toEqual({left: 0, top: 0}) - describe "::screenPositionForPixelPosition(pixelPosition)", -> it "converts pixel positions to screen positions", -> atom.styles.addStyleSheet """ @@ -197,15 +173,3 @@ describe "LinesYardstick", -> expect(linesYardstick.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2] expect(linesYardstick.screenPositionForPixelPosition(top: (editor.getLastScreenRow() + 1) * 14, left: 0)).toEqual [12, 2] expect(linesYardstick.screenPositionForPixelPosition(top: editor.getLastScreenRow() * 14, left: 0)).toEqual [12, 0] - - it "doesn't measure invisible lines if it is explicitly told so", -> - atom.styles.addStyleSheet """ - * { - font-size: 12px; - font-family: monospace; - } - """ - - expect(linesYardstick.screenPositionForPixelPosition({top: 0, left: 13}, true)).toEqual([0, 0]) - expect(linesYardstick.screenPositionForPixelPosition({top: 14, left: 20}, true)).toEqual([1, 0]) - expect(linesYardstick.screenPositionForPixelPosition({top: 28, left: 100}, true)).toEqual([2, 0]) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 2aeb8822e..effa579b1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -9,7 +9,7 @@ FakeLinesYardstick = require './fake-lines-yardstick' 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 "::getState()", -> + describe "::get(Pre|Post)MeasurementState()", -> [buffer, editor] = [] beforeEach -> @@ -25,6 +25,10 @@ describe "TextEditorPresenter", -> editor.destroy() buffer.destroy() + getState = (presenter) -> + presenter.getPreMeasurementState() + presenter.getPostMeasurementState() + buildPresenterWithoutMeasurements = (params={}) -> _.defaults params, model: editor @@ -279,7 +283,7 @@ describe "TextEditorPresenter", -> describe "during state retrieval", -> it "does not trigger onDidUpdateState events", -> presenter = buildPresenter() - expectNoStateUpdate presenter, -> presenter.getState() + expectNoStateUpdate presenter, -> getState(presenter) describe ".horizontalScrollbar", -> describe ".visible", -> @@ -292,19 +296,19 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false # ::contentFrameWidth itself is smaller than scrollWidth presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true # restore... presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10 + 1) - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false # visible vertical scrollbar makes the clientWidth smaller than the scrollWidth presenter.setExplicitHeight((editor.getLineCount() * 10) - 1) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true it "is false if the editor is mini", -> presenter = buildPresenter @@ -312,18 +316,18 @@ describe "TextEditorPresenter", -> contentFrameWidth: editor.getMaxScreenLineLength() * 10 - 10 baseCharacterWidth: 10 - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true editor.setMini(true) - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false editor.setMini(false) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true describe ".height", -> it "tracks the value of ::horizontalScrollbarHeight", -> presenter = buildPresenter(horizontalScrollbarHeight: 10) - expect(presenter.getState().horizontalScrollbar.height).toBe 10 + expect(getState(presenter).horizontalScrollbar.height).toBe 10 expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(20) - expect(presenter.getState().horizontalScrollbar.height).toBe 20 + expect(getState(presenter).horizontalScrollbar.height).toBe 20 describe ".right", -> it "is ::verticalScrollbarWidth if the vertical scrollbar is visible and 0 otherwise", -> @@ -335,27 +339,27 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().horizontalScrollbar.right).toBe 0 + expect(getState(presenter).horizontalScrollbar.right).toBe 0 presenter.setExplicitHeight((editor.getLineCount() * 10) - 1) - expect(presenter.getState().horizontalScrollbar.right).toBe 10 + expect(getState(presenter).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 = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 presenter = buildPresenter(contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when the ::contentFrameWidth changes", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when character widths change", -> waitsForPromise -> atom.packages.activatePackage('language-javascript') @@ -364,72 +368,72 @@ describe "TextEditorPresenter", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'support.function.js'], 'p', 20) presenter.characterWidthsChanged() - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide + expect(getState(presenter).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 = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the longest line changes", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setCursorBufferPosition([editor.getLongestScreenRow(), 0]) expectStateUpdate presenter, -> editor.insertText('xyz') - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 describe ".scrollLeft", -> it "tracks the value of ::scrollLeft", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 10 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(50) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 50 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 50 it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, explicitHeight: 100, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollLeftBefore = presenter.getState().horizontalScrollbar.scrollLeft + scrollLeftBefore = getState(presenter).horizontalScrollbar.scrollLeft expectStateUpdate presenter, -> editor.getBuffer().insert([6, 0], new Array(100).join('x')) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe scrollLeftBefore + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe scrollLeftBefore it "never goes negative", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(-300) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 0 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 0 it "is always 0 when soft wrapping is enabled", -> presenter = buildPresenter(scrollLeft: 0, verticalScrollbarWidth: 0, contentFrameWidth: 85, baseCharacterWidth: 10) editor.setSoftWrapped(false) presenter.setScrollLeft(Infinity) - expect(presenter.getState().content.scrollLeft).toBeGreaterThan 0 + expect(getState(presenter).content.scrollLeft).toBeGreaterThan 0 editor.setSoftWrapped(true) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 presenter.setScrollLeft(10) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 describe ".verticalScrollbar", -> describe ".visible", -> @@ -443,26 +447,26 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().verticalScrollbar.visible).toBe false + expect(getState(presenter).verticalScrollbar.visible).toBe false # ::explicitHeight itself is smaller than scrollWidth presenter.setExplicitHeight(editor.getLineCount() * 10 - 1) - expect(presenter.getState().verticalScrollbar.visible).toBe true + expect(getState(presenter).verticalScrollbar.visible).toBe true # restore... presenter.setExplicitHeight(editor.getLineCount() * 10) - expect(presenter.getState().verticalScrollbar.visible).toBe false + expect(getState(presenter).verticalScrollbar.visible).toBe false # visible horizontal scrollbar makes the clientHeight smaller than the scrollHeight presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().verticalScrollbar.visible).toBe true + expect(getState(presenter).verticalScrollbar.visible).toBe true describe ".width", -> it "is assigned based on ::verticalScrollbarWidth", -> presenter = buildPresenter(verticalScrollbarWidth: 10) - expect(presenter.getState().verticalScrollbar.width).toBe 10 + expect(getState(presenter).verticalScrollbar.width).toBe 10 expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(20) - expect(presenter.getState().verticalScrollbar.width).toBe 20 + expect(getState(presenter).verticalScrollbar.width).toBe 20 describe ".bottom", -> it "is ::horizontalScrollbarHeight if the horizontal scrollbar is visible and 0 otherwise", -> @@ -474,129 +478,129 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().verticalScrollbar.bottom).toBe 0 + expect(getState(presenter).verticalScrollbar.bottom).toBe 0 presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().verticalScrollbar.bottom).toBe 10 + expect(getState(presenter).verticalScrollbar.bottom).toBe 10 describe ".scrollHeight", -> it "is initialized based on the lineHeight, the number of lines, and the height", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 500) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe 500 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe 500 it "updates when the ::lineHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 20 it "updates when the line count changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 it "updates when ::explicitHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe 500 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe 500 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 20, horizontalScrollbarHeight: 10) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 10 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 50 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 50 it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().verticalScrollbar.scrollTop).toBe scrollTopBefore + expect(getState(presenter).verticalScrollbar.scrollTop).toBe scrollTopBefore it "never goes negative", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 0 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 0 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".hiddenInput", -> describe ".top/.left", -> it "is positioned over the last cursor it is in view and the editor is focused", -> editor.setCursorBufferPosition([3, 6]) presenter = buildPresenter(focused: false, explicitHeight: 50, contentFrameWidth: 300, horizontalScrollbarHeight: 0, verticalScrollbarWidth: 0) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> presenter.setFocused(true) - expectValues presenter.getState().hiddenInput, {top: 3 * 10, left: 6 * 10} + expectValues getState(presenter).hiddenInput, {top: 3 * 10, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollTop(15) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} + expectValues getState(presenter).hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollLeft(35) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} + expectValues getState(presenter).hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollTop(40) - expectValues presenter.getState().hiddenInput, {top: 0, left: (6 * 10) - 35} + expectValues getState(presenter).hiddenInput, {top: 0, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollLeft(70) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) - expectValues presenter.getState().hiddenInput, {top: 11 * 10 - presenter.getScrollTop(), left: 43 * 10 - presenter.getScrollLeft()} + expectValues getState(presenter).hiddenInput, {top: 11 * 10 - presenter.getScrollTop(), left: 43 * 10 - presenter.getScrollLeft()} newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) - expectValues presenter.getState().hiddenInput, {top: (6 * 10) - presenter.getScrollTop(), left: (10 * 10) - presenter.getScrollLeft()} + expectValues getState(presenter).hiddenInput, {top: (6 * 10) - presenter.getScrollTop(), left: (10 * 10) - presenter.getScrollLeft()} expectStateUpdate presenter, -> newCursor.destroy() - expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} + expectValues getState(presenter).hiddenInput, {top: 50 - 10, left: 300 - 10} expectStateUpdate presenter, -> presenter.setFocused(false) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} describe ".height", -> it "is assigned based on the line height", -> presenter = buildPresenter() - expect(presenter.getState().hiddenInput.height).toBe 10 + expect(getState(presenter).hiddenInput.height).toBe 10 expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().hiddenInput.height).toBe 20 + expect(getState(presenter).hiddenInput.height).toBe 20 describe ".width", -> it "is assigned based on the width of the character following the cursor", -> @@ -605,38 +609,38 @@ describe "TextEditorPresenter", -> runs -> editor.setCursorBufferPosition([3, 6]) presenter = buildPresenter() - expect(presenter.getState().hiddenInput.width).toBe 10 + expect(getState(presenter).hiddenInput.width).toBe 10 expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(15) - expect(presenter.getState().hiddenInput.width).toBe 15 + expect(getState(presenter).hiddenInput.width).toBe 15 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20) presenter.characterWidthsChanged() - expect(presenter.getState().hiddenInput.width).toBe 20 + expect(getState(presenter).hiddenInput.width).toBe 20 it "is 2px at the end of lines", -> presenter = buildPresenter() editor.setCursorBufferPosition([3, Infinity]) - expect(presenter.getState().hiddenInput.width).toBe 2 + expect(getState(presenter).hiddenInput.width).toBe 2 describe ".content", -> 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 + expect(getState(presenter).content.scrollingVertically).toBe true advanceClock(300) - expect(presenter.getState().content.scrollingVertically).toBe false + expect(getState(presenter).content.scrollingVertically).toBe false expectStateUpdate presenter, -> presenter.setScrollTop(0) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true presenter.setScrollTop(10) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true expectStateUpdate presenter, -> advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe false + expect(getState(presenter).content.scrollingVertically).toBe false describe ".maxHeight", -> it "changes based on boundingClientRect", -> @@ -644,55 +648,55 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setBoundingClientRect(left: 0, top: 0, height: 20, width: 0) - expect(presenter.getState().content.maxHeight).toBe(20) + expect(getState(presenter).content.maxHeight).toBe(20) expectStateUpdate presenter, -> presenter.setBoundingClientRect(left: 0, top: 0, height: 50, width: 0) - expect(presenter.getState().content.maxHeight).toBe(50) + expect(getState(presenter).content.maxHeight).toBe(50) describe ".scrollHeight", -> it "is initialized based on the lineHeight, the number of lines, and the height", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 10 presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 500) - expect(presenter.getState().content.scrollHeight).toBe 500 + expect(getState(presenter).content.scrollHeight).toBe 500 it "updates when the ::lineHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 20 it "updates when the line count changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 10 it "updates when ::explicitHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().content.scrollHeight).toBe 500 + expect(getState(presenter).content.scrollHeight).toBe 500 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight describe ".scrollWidth", -> it "is initialized as the max of the computed clientWidth and the width of the longest line", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(explicitHeight: 100, contentFrameWidth: 50, baseCharacterWidth: 10, verticalScrollbarWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 presenter = buildPresenter(explicitHeight: 100, contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10, verticalScrollbarWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 20 - 10 # subtract vertical scrollbar width + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 20 - 10 # subtract vertical scrollbar width describe "when the longest screen row is the first one and it's hidden", -> it "doesn't compute an invalid value (regression)", -> @@ -706,15 +710,15 @@ describe "TextEditorPresenter", -> """ expectStateUpdate presenter, -> presenter.setScrollTop(40) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the ::contentFrameWidth changes", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when character widths change", -> waitsForPromise -> atom.packages.activatePackage('language-javascript') @@ -723,109 +727,109 @@ describe "TextEditorPresenter", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'support.function.js'], 'p', 20) presenter.characterWidthsChanged() - expect(presenter.getState().content.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide + expect(getState(presenter).content.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 = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the longest line changes", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setCursorBufferPosition([editor.getLongestScreenRow(), 0]) expectStateUpdate presenter, -> editor.insertText('xyz') - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "isn't clipped to 0 when the longest line is folded (regression)", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) editor.foldBufferRow(0) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 describe ".scrollTop", -> it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) presenter.onDidChangeScrollTop -> presenter.setScrollTop(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update presenter.setScrollTop(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update expect(presenter.getScrollTop()).toBe(2) expect(presenter.getRealScrollTop()).toBe(1.5) it "changes based on the scroll operation that was performed last", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) presenter.setScrollTop(20) editor.setCursorBufferPosition([5, 0]) - expect(presenter.getState().content.scrollTop).toBe(50) + expect(getState(presenter).content.scrollTop).toBe(50) editor.setCursorBufferPosition([8, 0]) presenter.setScrollTop(10) - expect(presenter.getState().content.scrollTop).toBe(10) + expect(getState(presenter).content.scrollTop).toBe(10) it "corresponds to the passed logical coordinates when building the presenter", -> editor.setFirstVisibleScreenRow(4) presenter = buildPresenter(lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(40) + expect(getState(presenter).content.scrollTop).toBe(40) it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe 10 + expect(getState(presenter).content.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().content.scrollTop).toBe 50 + expect(getState(presenter).content.scrollTop).toBe 50 it "keeps the model up to date with the corresponding logical coordinates", -> presenter = buildPresenter(scrollTop: 0, explicitHeight: 20, horizontalScrollbarHeight: 10, lineHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(50) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenRow()).toBe 5 expectStateUpdate presenter, -> presenter.setScrollTop(57) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position 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) - expect(presenter.getState().content.scrollTop).toBe(80) + expect(getState(presenter).content.scrollTop).toBe(80) buffer.deleteRows(10, 9, 8) - expect(presenter.getState().content.scrollTop).toBe(60) + expect(getState(presenter).content.scrollTop).toBe(60) it "is always rounded to the nearest integer", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe 10 + expect(getState(presenter).content.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(11.4) - expect(presenter.getState().content.scrollTop).toBe 11 + expect(getState(presenter).content.scrollTop).toBe 11 expectStateUpdate presenter, -> presenter.setScrollTop(12.6) - expect(presenter.getState().content.scrollTop).toBe 13 + expect(getState(presenter).content.scrollTop).toBe 13 it "scrolls down automatically when the model is changed", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) editor.setText("") editor.insertNewline() - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) editor.insertNewline() - expect(presenter.getState().content.scrollTop).toBe(10) + expect(getState(presenter).content.scrollTop).toBe(10) it "never exceeds the computed scroll height minus the computed client height", -> didChangeScrollTopSpy = jasmine.createSpy() @@ -833,111 +837,111 @@ describe "TextEditorPresenter", -> presenter.onDidChangeScrollTop(didChangeScrollTopSpy) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().content.scrollTop).toBe scrollTopBefore + expect(getState(presenter).content.scrollTop).toBe scrollTopBefore expect(presenter.getRealScrollTop()).toBe scrollTopBefore expect(didChangeScrollTopSpy).not.toHaveBeenCalled() it "never goes negative", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().content.scrollTop).toBe 0 + expect(getState(presenter).content.scrollTop).toBe 0 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".scrollLeft", -> it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10) - expect(presenter.getState().content.scrollLeft).toBe(0) + expect(getState(presenter).content.scrollLeft).toBe(0) presenter.onDidChangeScrollLeft -> presenter.setScrollLeft(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update presenter.setScrollLeft(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update expect(presenter.getScrollLeft()).toBe(2) expect(presenter.getRealScrollLeft()).toBe(1.5) it "changes based on the scroll operation that was performed last", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10) - expect(presenter.getState().content.scrollLeft).toBe(0) + expect(getState(presenter).content.scrollLeft).toBe(0) presenter.setScrollLeft(20) editor.setCursorBufferPosition([0, 9]) - expect(presenter.getState().content.scrollLeft).toBe(90) + expect(getState(presenter).content.scrollLeft).toBe(90) editor.setCursorBufferPosition([0, 18]) presenter.setScrollLeft(50) - expect(presenter.getState().content.scrollLeft).toBe(50) + expect(getState(presenter).content.scrollLeft).toBe(50) it "corresponds to the passed logical coordinates when building the presenter", -> editor.setFirstVisibleScreenColumn(3) presenter = buildPresenter(lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().content.scrollLeft).toBe(30) + expect(getState(presenter).content.scrollLeft).toBe(30) it "tracks the value of ::scrollLeft", -> presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().content.scrollLeft).toBe 10 + expect(getState(presenter).content.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(50) - expect(presenter.getState().content.scrollLeft).toBe 50 + expect(getState(presenter).content.scrollLeft).toBe 50 it "keeps the model up to date with the corresponding logical coordinates", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(50) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenColumn()).toBe 5 expectStateUpdate presenter, -> presenter.setScrollLeft(57) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position 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) - expect(presenter.getState().content.scrollLeft).toBe 10 + expect(getState(presenter).content.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(11.4) - expect(presenter.getState().content.scrollLeft).toBe 11 + expect(getState(presenter).content.scrollLeft).toBe 11 expectStateUpdate presenter, -> presenter.setScrollLeft(12.6) - expect(presenter.getState().content.scrollLeft).toBe 13 + expect(getState(presenter).content.scrollLeft).toBe 13 it "never exceeds the computed scrollWidth minus the computed clientWidth", -> didChangeScrollLeftSpy = jasmine.createSpy() @@ -945,65 +949,65 @@ describe "TextEditorPresenter", -> presenter.onDidChangeScrollLeft(didChangeScrollLeftSpy) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollLeftBefore = presenter.getState().content.scrollLeft + scrollLeftBefore = getState(presenter).content.scrollLeft didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().insert([6, 0], new Array(100).join('x')) - expect(presenter.getState().content.scrollLeft).toBe scrollLeftBefore + expect(getState(presenter).content.scrollLeft).toBe scrollLeftBefore expect(presenter.getRealScrollLeft()).toBe scrollLeftBefore expect(didChangeScrollLeftSpy).not.toHaveBeenCalled() it "never goes negative", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(-300) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 describe ".indentGuidesVisible", -> it "is initialized based on the editor.showIndentGuide config setting", -> presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false atom.config.set('editor.showIndentGuide', true) presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true it "updates when the editor.showIndentGuide config setting changes", -> presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false expectStateUpdate presenter, -> atom.config.set('editor.showIndentGuide', true) - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true expectStateUpdate presenter, -> atom.config.set('editor.showIndentGuide', false) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false it "updates when the editor's grammar changes", -> atom.config.set('editor.showIndentGuide', true, scopeSelector: ".source.js") presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false stateUpdated = false presenter.onDidUpdateState -> stateUpdated = true @@ -1012,65 +1016,65 @@ describe "TextEditorPresenter", -> runs -> expect(stateUpdated).toBe true - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true expectStateUpdate presenter, -> editor.setGrammar(atom.grammars.selectGrammar('.txt')) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false it "is always false when the editor is mini", -> atom.config.set('editor.showIndentGuide', true) editor.setMini(true) presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false editor.setMini(false) - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true editor.setMini(true) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false describe ".backgroundColor", -> it "is assigned to ::backgroundColor unless the editor is mini", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' editor.setMini(true) presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBeNull() + expect(getState(presenter).content.backgroundColor).toBeNull() it "updates when ::backgroundColor changes", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).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)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(0, 0, 255, 0)' it "updates when ::mini changes", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' expectStateUpdate presenter, -> editor.setMini(true) - expect(presenter.getState().content.backgroundColor).toBeNull() + expect(getState(presenter).content.backgroundColor).toBeNull() describe ".placeholderText", -> it "is present when the editor has no text", -> editor.setPlaceholderText("the-placeholder-text") presenter = buildPresenter() - expect(presenter.getState().content.placeholderText).toBeNull() + expect(getState(presenter).content.placeholderText).toBeNull() expectStateUpdate presenter, -> editor.setText("") - expect(presenter.getState().content.placeholderText).toBe "the-placeholder-text" + expect(getState(presenter).content.placeholderText).toBe "the-placeholder-text" expectStateUpdate presenter, -> editor.setPlaceholderText("new-placeholder-text") - expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" + expect(getState(presenter).content.placeholderText).toBe "new-placeholder-text" describe ".tiles", -> lineStateForScreenRow = (presenter, row) -> lineId = presenter.model.tokenizedLineForScreenRow(row).id tileRow = presenter.tileForRow(row) - presenter.getState().content.tiles[tileRow]?.lines[lineId] + getState(presenter).content.tiles[tileRow]?.lines[lineId] - tiledContentContract (presenter) -> presenter.getState().content + tiledContentContract (presenter) -> getState(presenter).content describe "[tileId].lines[lineId]", -> # line state objects it "includes the state for visible lines in a tile", -> @@ -1330,7 +1334,7 @@ describe "TextEditorPresenter", -> describe ".cursors", -> stateForCursor = (presenter, cursorIndex) -> - presenter.getState().content.cursors[presenter.model.getCursors()[cursorIndex].id] + getState(presenter).content.cursors[presenter.model.getCursors()[cursorIndex].id] it "contains pixelRects for empty selections that are visible on screen", -> editor.setSelectedBufferRanges([ @@ -1350,31 +1354,31 @@ describe "TextEditorPresenter", -> it "is empty until all of the required measurements are assigned", -> presenter = buildPresenterWithoutMeasurements() - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setExplicitHeight(25) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setScrollTop(0) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setBaseCharacterWidth(8) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setBoundingClientRect(top: 0, left: 0, width: 500, height: 130) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setWindowSize(500, 130) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setVerticalScrollbarWidth(10) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setHorizontalScrollbarHeight(10) - expect(presenter.getState().content.cursors).not.toEqual({}) + expect(getState(presenter).content.cursors).not.toEqual({}) it "updates when ::scrollTop changes", -> editor.setSelectedBufferRanges([ @@ -1493,7 +1497,7 @@ describe "TextEditorPresenter", -> # destroying destroyedCursor = editor.getCursors()[2] expectStateUpdate presenter, -> destroyedCursor.destroy() - expect(presenter.getState().content.cursors[destroyedCursor.id]).toBeUndefined() + expect(getState(presenter).content.cursors[destroyedCursor.id]).toBeUndefined() it "makes cursors as wide as the ::baseCharacterWidth if they're at the end of a line", -> editor.setCursorBufferPosition([1, Infinity]) @@ -1507,27 +1511,27 @@ describe "TextEditorPresenter", -> presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay}) presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> presenter.setFocused(false) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false it "stops alternating for ::cursorBlinkResumeDelay when a cursor moves or a cursor is added", -> cursorBlinkPeriod = 100 @@ -1535,46 +1539,46 @@ describe "TextEditorPresenter", -> presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay}) presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> editor.moveRight() - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkResumeDelay) advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> editor.addCursorAtBufferPosition([1, 0]) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkResumeDelay) advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false describe ".highlights", -> expectUndefinedStateForHighlight = (presenter, decoration) -> - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles state = stateForHighlightInTile(presenter, decoration, tileId) expect(state).toBeUndefined() stateForHighlightInTile = (presenter, decoration, tile) -> - presenter.getState().content.tiles[tile]?.highlights[decoration.id] + getState(presenter).content.tiles[tile]?.highlights[decoration.id] stateForSelectionInTile = (presenter, selectionIndex, tile) -> selection = presenter.model.getSelections()[selectionIndex] stateForHighlightInTile(presenter, selection.decoration, tile) expectUndefinedStateForSelection = (presenter, selectionIndex) -> - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles state = stateForSelectionInTile(presenter, selectionIndex, tileId) expect(state).toBeUndefined() @@ -1684,24 +1688,24 @@ describe "TextEditorPresenter", -> ]) presenter = buildPresenterWithoutMeasurements(tileSize: 2) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setExplicitHeight(25) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setLineHeight(10) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setScrollTop(0) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setBaseCharacterWidth(8) assignedAnyHighlight = false - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles assignedAnyHighlight ||= _.isEqual(tileState.highlights, {}) expect(assignedAnyHighlight).toBe(true) @@ -1916,7 +1920,7 @@ describe "TextEditorPresenter", -> describe ".overlays", -> [item] = [] stateForOverlay = (presenter, decoration) -> - presenter.getState().content.overlays[decoration.id] + getState(presenter).content.overlays[decoration.id] it "contains state for overlay decorations both initially and when their markers move", -> marker = editor.addMarkerLayer(maintainHistory: true).markBufferPosition([2, 13], invalidate: 'touch') @@ -2023,25 +2027,25 @@ describe "TextEditorPresenter", -> decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) presenter = buildPresenterWithoutMeasurements() - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setBaseCharacterWidth(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setWindowSize(500, 100) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setVerticalScrollbarWidth(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setHorizontalScrollbarHeight(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500}) - expect(presenter.getState().content.overlays).not.toEqual({}) + expect(getState(presenter).content.overlays).not.toEqual({}) describe "when the overlay has been measured", -> [gutterWidth, windowWidth, windowHeight, itemWidth, itemHeight, contentMargin, boundingClientRect, contentFrameWidth] = [] @@ -2210,52 +2214,52 @@ describe "TextEditorPresenter", -> it "updates model's rows per page when it changes", -> presenter = buildPresenter(explicitHeight: 50, lineHeightInPixels: 10, horizontalScrollbarHeight: 10) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(4) presenter.setExplicitHeight(100) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(9) presenter.setHorizontalScrollbarHeight(0) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(10) presenter.setLineHeight(5) - presenter.getState() # trigger state update + getState(presenter) # trigger state update 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) presenter.setAutoHeight(true) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 10 expectStateUpdate presenter, -> presenter.setAutoHeight(false) - expect(presenter.getState().height).toBe null + expect(getState(presenter).height).toBe null expectStateUpdate presenter, -> presenter.setAutoHeight(true) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 10 expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 20 expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 20 describe ".focused", -> it "tracks the value of ::focused", -> presenter = buildPresenter() presenter.setFocused(false) - expect(presenter.getState().focused).toBe false + expect(getState(presenter).focused).toBe false expectStateUpdate presenter, -> presenter.setFocused(true) - expect(presenter.getState().focused).toBe true + expect(getState(presenter).focused).toBe true expectStateUpdate presenter, -> presenter.setFocused(false) - expect(presenter.getState().focused).toBe false + expect(getState(presenter).focused).toBe false describe ".gutters", -> getStateForGutterWithName = (presenter, gutterName) -> - gutterDescriptions = presenter.getState().gutters + gutterDescriptions = getState(presenter).gutters for description in gutterDescriptions gutter = description.gutter return description if gutter.name is gutterName @@ -2267,7 +2271,7 @@ describe "TextEditorPresenter", -> gutter2 = editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) expectedGutterOrder = [gutter1, editor.gutterWithName('line-number'), gutter2] - for gutterDescription, index in presenter.getState().gutters + for gutterDescription, index in getState(presenter).gutters expect(gutterDescription.gutter).toEqual expectedGutterOrder[index] it "updates when the visibility of a gutter changes", -> @@ -2286,7 +2290,7 @@ describe "TextEditorPresenter", -> describe "for a gutter description that corresponds to the line-number gutter", -> getLineNumberGutterState = (presenter) -> - gutterDescriptions = presenter.getState().gutters + gutterDescriptions = getState(presenter).gutters for description in gutterDescriptions gutter = description.gutter return description if gutter.name is 'line-number' @@ -2614,7 +2618,7 @@ describe "TextEditorPresenter", -> decoration3 = editor.decorateMarker(marker3, decorationParams) # Clear any batched state updates. - presenter.getState() + getState(presenter) it "contains all decorations within the visible buffer range", -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') @@ -2915,7 +2919,7 @@ describe "TextEditorPresenter", -> expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe scrollTopBefore expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe scrollTopBefore @@ -3016,7 +3020,7 @@ describe "TextEditorPresenter", -> expectValidState = -> presenterParams.scrollTop = presenter.scrollTop presenterParams.scrollLeft = presenter.scrollLeft - actualState = presenter.getState() + actualState = getState(presenter) expectedState = new TextEditorPresenter(presenterParams).state delete actualState.content.scrollingVertically delete expectedState.content.scrollingVertically diff --git a/src/lines-yardstick.coffee b/src/lines-yardstick.coffee index 54ba6cf57..bd8219e81 100644 --- a/src/lines-yardstick.coffee +++ b/src/lines-yardstick.coffee @@ -3,7 +3,7 @@ TokenIterator = require './token-iterator' module.exports = class LinesYardstick - constructor: (@model, @presenter, @lineNodesProvider, grammarRegistry) -> + constructor: (@model, @lineNodesProvider, grammarRegistry) -> @tokenIterator = new TokenIterator({grammarRegistry}) @rangeForMeasurement = document.createRange() @invalidateCache() @@ -11,14 +11,12 @@ class LinesYardstick invalidateCache: -> @pixelPositionsByLineIdAndColumn = {} - prepareScreenRowsForMeasurement: (screenRows) -> - @presenter.setScreenRowsToMeasure(screenRows) - @lineNodesProvider.updateSync(@presenter.getPreMeasurementState()) + measuredRowForPixelPosition: (pixelPosition) -> + targetTop = pixelPosition.top + row = Math.floor(targetTop / @model.getLineHeightInPixels()) + row if 0 <= row <= @model.getLastScreenRow() - clearScreenRowsForMeasurement: -> - @presenter.clearScreenRowsToMeasure() - - screenPositionForPixelPosition: (pixelPosition, measureVisibleLinesOnly) -> + screenPositionForPixelPosition: (pixelPosition) -> targetTop = pixelPosition.top targetLeft = pixelPosition.left defaultCharWidth = @model.getDefaultCharWidth() @@ -28,12 +26,10 @@ class LinesYardstick row = Math.min(row, @model.getLastScreenRow()) row = Math.max(0, row) - @prepareScreenRowsForMeasurement([row]) unless measureVisibleLinesOnly - line = @model.tokenizedLineForScreenRow(row) lineNode = @lineNodesProvider.lineNodeForLineIdAndScreenRow(line?.id, row) - return new Point(row, 0) unless lineNode? and line? + return Point(row, 0) unless lineNode? and line? textNodes = @lineNodesProvider.textNodesForLineIdAndScreenRow(line.id, row) column = 0 @@ -70,33 +66,27 @@ class LinesYardstick left = @leftPixelPositionForCharInTextNode(lineNode, textNode, indexWithinTextNode) charWidth = left - previousLeft - return new Point(row, previousColumn) if targetLeft <= previousLeft + (charWidth / 2) + return Point(row, previousColumn) if targetLeft <= previousLeft + (charWidth / 2) previousLeft = left previousColumn = column column += charLength - @clearScreenRowsForMeasurement() unless measureVisibleLinesOnly - if targetLeft <= previousLeft + (charWidth / 2) - new Point(row, previousColumn) + Point(row, previousColumn) else - new Point(row, column) + Point(row, column) - pixelPositionForScreenPosition: (screenPosition, clip=true, measureVisibleLinesOnly) -> + pixelPositionForScreenPosition: (screenPosition, clip=true) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip targetRow = screenPosition.row targetColumn = screenPosition.column - @prepareScreenRowsForMeasurement([targetRow]) unless measureVisibleLinesOnly - top = targetRow * @model.getLineHeightInPixels() left = @leftPixelPositionForScreenPosition(targetRow, targetColumn) - @clearScreenRowsForMeasurement() unless measureVisibleLinesOnly - {top, left} leftPixelPositionForScreenPosition: (row, column) -> @@ -173,18 +163,3 @@ class LinesYardstick offset = lineNode.getBoundingClientRect().left left + width - offset - - pixelRectForScreenRange: (screenRange, measureVisibleLinesOnly) -> - lineHeight = @model.getLineHeightInPixels() - - if screenRange.end.row > screenRange.start.row - top = @pixelPositionForScreenPosition(screenRange.start, true, measureVisibleLinesOnly).top - left = 0 - height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight - width = @presenter.getScrollWidth() - else - {top, left} = @pixelPositionForScreenPosition(screenRange.start, false, measureVisibleLinesOnly) - height = lineHeight - width = @pixelPositionForScreenPosition(screenRange.end, false, measureVisibleLinesOnly).left - left - - {top, left, width, height} diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 430b0c0fd..6a84c8dac 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -82,7 +82,7 @@ class TextEditorComponent @linesComponent = new LinesComponent({@presenter, @hostElement, @useShadowDOM, @domElementPool, @assert, @grammars}) @scrollViewNode.appendChild(@linesComponent.getDomNode()) - @linesYardstick = new LinesYardstick(@editor, @presenter, @linesComponent, @grammars) + @linesYardstick = new LinesYardstick(@editor, @linesComponent, @grammars) @presenter.setLinesYardstick(@linesYardstick) @horizontalScrollbarComponent = new ScrollbarComponent({orientation: 'horizontal', onScroll: @onHorizontalScroll}) @@ -127,8 +127,10 @@ class TextEditorComponent @domNode updateSync: -> + @updateSyncPreMeasurement() + @oldState ?= {} - @newState = @presenter.getState() + @newState = @presenter.getPostMeasurementState() if @editor.getLastSelection()? and not @editor.getLastSelection().isEmpty() @domNode.classList.add('has-selection') @@ -170,6 +172,9 @@ class TextEditorComponent @updateParentViewFocusedClassIfNeeded() @updateParentViewMiniClass() + updateSyncPreMeasurement: -> + @linesComponent.updateSync(@presenter.getPreMeasurementState()) + readAfterUpdateSync: => @overlayManager?.measureOverlays() @@ -429,14 +434,42 @@ class TextEditorComponent getVisibleRowRange: -> @presenter.getVisibleRowRange() - pixelPositionForScreenPosition: -> - @linesYardstick.pixelPositionForScreenPosition(arguments...) + pixelPositionForScreenPosition: (screenPosition, clip) -> + unless @presenter.isRowVisible(screenPosition.row) + @presenter.setScreenRowsToMeasure([screenPosition.row]) + @updateSyncPreMeasurement() - screenPositionForPixelPosition: -> - @linesYardstick.screenPositionForPixelPosition(arguments...) + pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition, clip) + @presenter.clearScreenRowsToMeasure() + pixelPosition - pixelRectForScreenRange: -> - @linesYardstick.pixelRectForScreenRange(arguments...) + screenPositionForPixelPosition: (pixelPosition) -> + row = @linesYardstick.measuredRowForPixelPosition(pixelPosition) + if row? and not @presenter.isRowVisible(row) + @presenter.setScreenRowsToMeasure([row]) + @updateSyncPreMeasurement() + + position = @linesYardstick.screenPositionForPixelPosition(pixelPosition) + @presenter.clearScreenRowsToMeasure() + position + + pixelRectForScreenRange: (screenRange) -> + rowsToMeasure = [] + unless @presenter.isRowVisible(screenRange.start.row) + rowsToMeasure.push(screenRange.start.row) + unless @presenter.isRowVisible(screenRange.end.row) + rowsToMeasure.push(screenRange.end.row) + + if rowsToMeasure.length > 0 + @presenter.setScreenRowsToMeasure(rowsToMeasure) + @updateSyncPreMeasurement() + + rect = @presenter.absolutePixelRectForScreenRange(screenRange) + + if rowsToMeasure.length > 0 + @presenter.clearScreenRowsToMeasure() + + rect pixelRangeForScreenRange: (screenRange, clip=true) -> {start, end} = Range.fromObject(screenRange) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 405e34548..5cfaeebcf 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -121,14 +121,6 @@ class TextEditorPresenter @updating = false @resetTrackedUpdates() - - # Public: Gets this presenter's state, updating it just in time before returning from this function. - # Returns a state {Object}, useful for rendering to screen. - getState: -> - @linesYardstick.prepareScreenRowsForMeasurement() - - @getPostMeasurementState() - @state resetTrackedUpdates: -> @@ -1155,16 +1147,29 @@ class TextEditorPresenter hasOverlayPositionRequirements: -> @hasPixelRectRequirements() and @boundingClientRect? and @windowWidth and @windowHeight + absolutePixelRectForScreenRange: (screenRange) -> + lineHeight = @model.getLineHeightInPixels() + + if screenRange.end.row > screenRange.start.row + top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, true).top + left = 0 + height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight + width = @getScrollWidth() + else + {top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, false) + height = lineHeight + width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end, false).left - left + + {top, left, width, height} + pixelRectForScreenRange: (screenRange) -> - rect = @linesYardstick.pixelRectForScreenRange(screenRange, true) + rect = @absolutePixelRectForScreenRange(screenRange) rect.top -= @getScrollTop() rect.left -= @getScrollLeft() - rect.top = Math.round(rect.top) rect.left = Math.round(rect.left) rect.width = Math.round(rect.width) rect.height = Math.round(rect.height) - rect fetchDecorations: -> @@ -1550,3 +1555,6 @@ class TextEditorPresenter getVisibleRowRange: -> [@startRow, @endRow] + + isRowVisible: (row) -> + @startRow <= row < @endRow