From e5ab835357ace03e63c51b4ea060f2aa424866bb Mon Sep 17 00:00:00 2001 From: Mike J Innes Date: Fri, 27 May 2016 00:05:12 +0100 Subject: [PATCH 1/5] add `stable` option --- src/text-editor-presenter.coffee | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index cc988bbea..07499c822 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -451,7 +451,7 @@ class TextEditorPresenter for decoration in @model.getOverlayDecorations() continue unless decoration.getMarker().isValid() - {item, position, class: klass} = decoration.getProperties() + {item, position, class: klass, stable} = decoration.getProperties() if position is 'tail' screenPosition = decoration.getMarker().getTailScreenPosition() else @@ -466,15 +466,17 @@ class TextEditorPresenter if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - rightDiff = left + itemWidth + contentMargin - @windowWidth - left -= rightDiff if rightDiff > 0 + if !stable - leftDiff = left + contentMargin - left -= leftDiff if leftDiff < 0 + rightDiff = left + itemWidth + contentMargin - @windowWidth + left -= rightDiff if rightDiff > 0 - if top + itemHeight > @windowHeight and - top - (itemHeight + @lineHeight) >= 0 - top -= itemHeight + @lineHeight + leftDiff = left + contentMargin + left -= leftDiff if leftDiff < 0 + + if top + itemHeight > @windowHeight and + top - (itemHeight + @lineHeight) >= 0 + top -= itemHeight + @lineHeight pixelPosition.top = top pixelPosition.left = left From 20545ad41dfb5db863ee0ded914d2b2dea5accbe Mon Sep 17 00:00:00 2001 From: Mike J Innes Date: Fri, 26 Aug 2016 17:38:50 +0100 Subject: [PATCH 2/5] Update text-editor-presenter.coffee --- src/text-editor-presenter.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 07499c822..814a2d220 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -466,7 +466,7 @@ class TextEditorPresenter if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - if !stable + if not stable rightDiff = left + itemWidth + contentMargin - @windowWidth left -= rightDiff if rightDiff > 0 From f9ef678c4a3005184f739641121a88f0859deab8 Mon Sep 17 00:00:00 2001 From: Mike J Innes Date: Mon, 28 Nov 2016 10:24:51 +0000 Subject: [PATCH 3/5] scroll test --- spec/text-editor-presenter-spec.coffee | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 9eb4a15d2..d9529b2a0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2536,6 +2536,49 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth} } + it "does not slide horizontally when set to stable", -> + scrollLeft = 20 + marker = editor.markBufferPosition([0, 26], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item, stable: true}) + + presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} + } + + expectStateUpdate presenter, -> editor.insertText('a') + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} + } + + it "does not flip vertically when set to stable", -> + scrollTop = 10 + marker = editor.markBufferPosition([5, 0], invalidate: 'never') + decoration = editor.decorateMarker(marker, {type: 'overlay', item, stable: true}) + + presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) + expectStateUpdate presenter, -> + presenter.setOverlayDimensions(decoration.id, itemWidth, itemHeight, contentMargin) + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 6 * 10 - scrollTop, left: gutterWidth} + } + + expectStateUpdate presenter, -> + editor.insertNewline() + presenter.setScrollTop(scrollTop) # I'm fighting the editor + + expectValues stateForOverlay(presenter, decoration), { + item: item + pixelPosition: {top: 6 * 10 - scrollTop, left: gutterWidth} + } + describe "when the overlay item has a margin", -> beforeEach -> itemWidth = 12 * 10 From f4c45c1e39b8aaae9d569c11c285d2683a8f5090 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 28 Nov 2016 12:45:05 -0700 Subject: [PATCH 4/5] Rename `stable: true` to `avoidOverlay: false` and fix tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of the test fixes, I’m honoring the `autoscroll: false` option in `insertText` and `insertNewline` to avoid inadvertently scrolling the editor during tests when the editor is modified. --- spec/text-editor-presenter-spec.coffee | 24 +++++++++++------------- src/selection.coffee | 4 ++-- src/text-editor-presenter.coffee | 5 ++--- src/text-editor.coffee | 4 ++-- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index d9529b2a0..d688d8182 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -2501,13 +2501,13 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} } - expectStateUpdate presenter, -> editor.insertText('a') + expectStateUpdate presenter, -> editor.insertText('abc', autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} } - expectStateUpdate presenter, -> editor.insertText('b') + expectStateUpdate presenter, -> editor.insertText('d', autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 1 * 10, left: windowWidth - itemWidth} @@ -2528,18 +2528,17 @@ describe "TextEditorPresenter", -> } expectStateUpdate presenter, -> - editor.insertNewline() - presenter.setScrollTop(scrollTop) # I'm fighting the editor + editor.insertNewline(autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item pixelPosition: {top: 6 * 10 - scrollTop - itemHeight, left: gutterWidth} } - it "does not slide horizontally when set to stable", -> + it "when avoidOverflow is false, does not move horizontally when overflowing the editor's scrollView horizontally", -> scrollLeft = 20 marker = editor.markBufferPosition([0, 26], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item, stable: true}) + decoration = editor.decorateMarker(marker, {type: 'overlay', item, avoidOverflow: false}) presenter = buildPresenter({scrollLeft, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> @@ -2550,16 +2549,16 @@ describe "TextEditorPresenter", -> pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} } - expectStateUpdate presenter, -> editor.insertText('a') + expectStateUpdate presenter, -> editor.insertText('a', autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 1 * 10, left: 26 * 10 + gutterWidth - scrollLeft} + pixelPosition: {top: 1 * 10, left: 27 * 10 + gutterWidth - scrollLeft} } - it "does not flip vertically when set to stable", -> + it "when avoidOverflow is false, does not flip vertically when overflowing the editor's scrollView vertically", -> scrollTop = 10 marker = editor.markBufferPosition([5, 0], invalidate: 'never') - decoration = editor.decorateMarker(marker, {type: 'overlay', item, stable: true}) + decoration = editor.decorateMarker(marker, {type: 'overlay', item, avoidOverflow: false}) presenter = buildPresenter({scrollTop, windowWidth, windowHeight, contentFrameWidth, boundingClientRect, gutterWidth}) expectStateUpdate presenter, -> @@ -2571,12 +2570,11 @@ describe "TextEditorPresenter", -> } expectStateUpdate presenter, -> - editor.insertNewline() - presenter.setScrollTop(scrollTop) # I'm fighting the editor + editor.insertNewline(autoscroll: false) expectValues stateForOverlay(presenter, decoration), { item: item - pixelPosition: {top: 6 * 10 - scrollTop, left: gutterWidth} + pixelPosition: {top: 7 * 10 - scrollTop, left: gutterWidth} } describe "when the overlay item has a margin", -> diff --git a/src/selection.coffee b/src/selection.coffee index 5eaa9c8dd..8aa86157e 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -366,7 +366,7 @@ class Selection extends Model insertText: (text, options={}) -> oldBufferRange = @getBufferRange() wasReversed = @isReversed() - @clear() + @clear(options) autoIndentFirstLine = false precedingText = @editor.getTextInRange([[oldBufferRange.start.row, 0], oldBufferRange.start]) @@ -403,7 +403,7 @@ class Selection extends Model else if options.autoDecreaseIndent and NonWhitespaceRegExp.test(text) @editor.autoDecreaseIndentForBufferRow(newBufferRange.start.row) - @autoscroll() if @isLastSelection() + @autoscroll() if options.autoscroll ? @isLastSelection() newBufferRange diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 814a2d220..fadcfc6da 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -451,7 +451,7 @@ class TextEditorPresenter for decoration in @model.getOverlayDecorations() continue unless decoration.getMarker().isValid() - {item, position, class: klass, stable} = decoration.getProperties() + {item, position, class: klass, avoidOverflow} = decoration.getProperties() if position is 'tail' screenPosition = decoration.getMarker().getTailScreenPosition() else @@ -466,8 +466,7 @@ class TextEditorPresenter if overlayDimensions = @overlayDimensions[decoration.id] {itemWidth, itemHeight, contentMargin} = overlayDimensions - if not stable - + if avoidOverflow isnt false rightDiff = left + itemWidth + contentMargin - @windowWidth left -= rightDiff if rightDiff > 0 diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 497dd3c20..78360efbd 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1085,8 +1085,8 @@ class TextEditor extends Model ) # Essential: For each selection, replace the selected text with a newline. - insertNewline: -> - @insertText('\n') + insertNewline: (options) -> + @insertText('\n', options) # Essential: For each selection, if the selection is empty, delete the character # following the cursor. Otherwise delete the selected text. From a8930dfebac99eb94491b411dc357ea2dd52b63f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 28 Nov 2016 15:08:34 -0700 Subject: [PATCH 5/5] Document avoidOverflow option --- src/text-editor.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 78360efbd..f09ca9c2a 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -1749,10 +1749,14 @@ class TextEditor extends Model # * `onlyNonEmpty` (optional) If `true`, the decoration will only be applied # if the associated `DisplayMarker` is non-empty. Only applicable to the # `gutter`, `line`, and `line-number` types. - # * `position` (optional) Only applicable to decorations of type `overlay` and `block`, - # controls where the view is positioned relative to the `TextEditorMarker`. + # * `position` (optional) Only applicable to decorations of type `overlay` and `block`. + # Controls where the view is positioned relative to the `TextEditorMarker`. # Values can be `'head'` (the default) or `'tail'` for overlay decorations, and # `'before'` (the default) or `'after'` for block decorations. + # * `avoidOverflow` (optional) Only applicable to decorations of type + # `overlay`. Determines whether the decoration adjusts its horizontal or + # vertical position to remain fully visible when it would otherwise + # overflow the editor. Defaults to `true`. # # Returns a {Decoration} object decorateMarker: (marker, decorationParams) ->