From ac2559600261fdac897ab8e263e02513c3fd3826 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 27 Jan 2015 17:26:54 -0700 Subject: [PATCH] Wait for required measurements before building some presenter state Signed-off-by: Max Brunsfeld --- spec/text-editor-presenter-spec.coffee | 99 ++++++++++++++++++++++++++ src/text-editor-presenter.coffee | 13 +++- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 723e33f49..5345f32ca 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -284,6 +284,19 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 0)).toBeDefined() expect(lineStateForScreenRow(presenter, 12)).toBeDefined() + it "is empty until all of the required measurements are assigned", -> + presenter = new TextEditorPresenter(model: editor, lineOverdrawMargin: 1, baseCharacterWidth: 10) + expect(presenter.state.content.lines).toEqual({}) + + presenter.setClientHeight(25) + expect(presenter.state.content.lines).toEqual({}) + + presenter.setLineHeight(10) + expect(presenter.state.content.lines).toEqual({}) + + presenter.setScrollTop(0) + expect(presenter.state.content.lines).not.toEqual({}) + it "updates when ::scrollTop changes", -> presenter = new TextEditorPresenter(model: editor, clientHeight: 25, scrollTop: 0, lineHeight: 10, lineOverdrawMargin: 1) @@ -509,6 +522,22 @@ describe "TextEditorPresenter", -> expect(stateForCursor(presenter, 3)).toEqual {top: 5 * 10, left: 12 * 10, width: 10, height: 10} expect(stateForCursor(presenter, 4)).toBeUndefined() + it "is empty until all of the required measurements are assigned", -> + presenter = new TextEditorPresenter(model: editor, lineOverdrawMargin: 1) + expect(presenter.state.content.cursors).toEqual({}) + + presenter.setClientHeight(25) + expect(presenter.state.content.cursors).toEqual({}) + + presenter.setLineHeight(10) + expect(presenter.state.content.cursors).toEqual({}) + + presenter.setScrollTop(0) + expect(presenter.state.content.cursors).toEqual({}) + + presenter.setBaseCharacterWidth(8) + expect(presenter.state.content.cursors).not.toEqual({}) + it "updates when ::scrollTop changes", -> editor.setSelectedBufferRanges([ [[1, 2], [1, 2]], @@ -754,6 +783,26 @@ describe "TextEditorPresenter", -> expect(stateForHighlight(presenter, highlight7)).toBeUndefined() expect(stateForHighlight(presenter, highlight8)).toBeUndefined() + it "is empty until all of the required measurements are assigned", -> + editor.setSelectedBufferRanges([ + [[0, 2], [2, 4]], + ]) + + presenter = new TextEditorPresenter(model: editor, lineOverdrawMargin: 1) + expect(presenter.state.content.highlights).toEqual({}) + + presenter.setClientHeight(25) + expect(presenter.state.content.highlights).toEqual({}) + + presenter.setLineHeight(10) + expect(presenter.state.content.highlights).toEqual({}) + + presenter.setScrollTop(0) + expect(presenter.state.content.highlights).toEqual({}) + + presenter.setBaseCharacterWidth(8) + expect(presenter.state.content.highlights).not.toEqual({}) + it "does not include highlights for invalid markers", -> marker = editor.markBufferRange([[2, 2], [2, 4]], invalidate: 'touch') highlight = editor.decorateMarker(marker, type: 'highlight', class: 'h') @@ -985,6 +1034,42 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 2 * 10, left: 13 * 10} } + it "updates when ::baseCharacterWidth changes", -> + item = {} + marker = editor.markBufferPosition([2, 13], invalidate: 'touch') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + presenter = new TextEditorPresenter(model: editor, clientHeight: 30, scrollTop: 20, lineHeight: 10, lineOverdrawMargin: 0, baseCharacterWidth: 10) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 2 * 10, left: 13 * 10} + } + + expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(5) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 2 * 10, left: 13 * 5} + } + + it "updates when ::lineHeight changes", -> + item = {} + marker = editor.markBufferPosition([2, 13], invalidate: 'touch') + decoration = editor.decorateMarker(marker, {type: 'overlay', item}) + presenter = new TextEditorPresenter(model: editor, clientHeight: 30, scrollTop: 20, lineHeight: 10, lineOverdrawMargin: 0, baseCharacterWidth: 10) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 2 * 10, left: 13 * 10} + } + + expectStateUpdate presenter, -> presenter.setLineHeight(5) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 2 * 5, left: 13 * 10} + } + it "honors the 'position' option on overlay decorations", -> item = {} marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') @@ -995,6 +1080,20 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 2 * 10, left: 13 * 10} } + it "is empty until all of the required measurements are assigned", -> + item = {} + marker = editor.markBufferRange([[2, 13], [4, 14]], invalidate: 'touch') + decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) + + presenter = new TextEditorPresenter(model: editor, lineOverdrawMargin: 0, scrollTop: 0, scrollHeight: 50) + expect(presenter.state.content.overlays).toEqual({}) + + presenter.setBaseCharacterWidth(10) + expect(presenter.state.content.overlays).toEqual({}) + + presenter.setLineHeight(10) + expect(presenter.state.content.overlays).not.toEqual({}) + describe ".gutter", -> describe ".backgroundColor", -> it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 21bc824b0..01bc6fced 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -121,9 +121,11 @@ class TextEditorPresenter decorationClasses: @lineDecorationClassesForRow(row) updateCursorsState: -> + @state.content.cursors = {} + return unless @hasRequiredMeasurements() + startRow = @getStartRow() endRow = @getEndRow() - @state.content.cursors = {} for cursor in @model.getCursors() if cursor.isVisible() and startRow <= cursor.getScreenRow() < endRow @@ -134,6 +136,8 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateHighlightsState: -> + return unless @hasRequiredMeasurements() + startRow = @getStartRow() endRow = @getEndRow() visibleHighlights = {} @@ -169,6 +173,8 @@ class TextEditorPresenter @emitter.emit 'did-update-state' updateOverlaysState: -> + return unless @hasRequiredMeasurements() + visibleDecorationIds = {} for decoration in @model.getOverlayDecorations() @@ -337,6 +343,9 @@ class TextEditorPresenter getCursorBlinkResumeDelay: -> @cursorBlinkResumeDelay + hasRequiredMeasurements: -> + @getLineHeight()? and @getBaseCharacterWidth()? and @getClientHeight()? and @getScrollTop()? + setScrollTop: (@scrollTop) -> @didStartScrolling() @updateVerticalScrollState() @@ -396,6 +405,7 @@ class TextEditorPresenter @updateCursorsState() @updateHighlightsState() @updateLineNumbersState() + @updateOverlaysState() getLineHeight: -> @lineHeight @@ -432,6 +442,7 @@ class TextEditorPresenter @updateLinesState() @updateCursorsState() @updateHighlightsState() + @updateOverlaysState() clearScopedCharWidths: -> @charWidthsByScope = {}