From 56020b11b0e2d1d43c69df54b550995cfab5f2f7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:36:55 +0100 Subject: [PATCH 1/4] :bug: Avoid soft-wrapping on indentation --- spec/display-buffer-spec.coffee | 18 ++++++++++++++++++ src/tokenized-line.coffee | 26 +++++++++++++++----------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 1703a24d1..95f22acca 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -115,6 +115,24 @@ describe "DisplayBuffer", -> expect(displayBuffer.tokenizedLineForScreenRow(3).text).toBe ' var pivot = items.shift(), current, left = [], ' expect(displayBuffer.tokenizedLineForScreenRow(4).text).toBe ' right = [];' + describe "when the only whitespace characters are at the beginning of the line", -> + beforeEach -> + displayBuffer.setEditorWidthInChars(10) + + it "wraps the line at the max length when indented with tabs", -> + buffer.setTextInRange([[0, 0], [1, 0]], '\t\tabcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + + it "wraps the line at the max length when indented with spaces", -> + buffer.setTextInRange([[0, 0], [1, 0]], ' abcdefghijklmnopqrstuvwxyz') + + expect(displayBuffer.tokenizedLineForScreenRow(0).text).toBe ' abcdef' + expect(displayBuffer.tokenizedLineForScreenRow(1).text).toBe ' ghijkl' + expect(displayBuffer.tokenizedLineForScreenRow(2).text).toBe ' mnopqr' + describe "when there are hard tabs", -> beforeEach -> buffer.setText(buffer.getText().replace(new RegExp(' ', 'g'), '\t')) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 2a807d84a..513ad5b4b 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -106,7 +106,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column) + for column in [maxColumn..0] when @isColumnOutsideIndentation(column) return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -127,12 +127,13 @@ class TokenizedLine rightTokens = new Array(@tokens...) leftTokens = [] - leftTextLength = 0 - while leftTextLength < column - if leftTextLength + rightTokens[0].value.length > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength) + leftScreenColumn = 0 + + while leftScreenColumn < column + if leftScreenColumn + rightTokens[0].screenDelta > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) nextToken = rightTokens.shift() - leftTextLength += nextToken.value.length + leftScreenColumn += nextToken.screenDelta leftTokens.push nextToken indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) @@ -160,6 +161,9 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null + isColumnOutsideIndentation: (column) -> + column >= @firstNonWhitespaceIndex and @isColumnOutsideSoftWrapIndentation(column) + isColumnOutsideSoftWrapIndentation: (column) -> return true if @softWrapIndentationTokens.length == 0 @@ -209,15 +213,15 @@ class TokenizedLine outputTokens markLeadingAndTrailingWhitespaceTokens: -> - firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) - if firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, firstNonWhitespaceIndex - 1) - firstNonWhitespaceIndex-- + @firstNonWhitespaceIndex = @text.search(NonWhitespaceRegex) + if @firstNonWhitespaceIndex > 0 and isPairedCharacter(@text, @firstNonWhitespaceIndex - 1) + @firstNonWhitespaceIndex-- firstTrailingWhitespaceIndex = @text.search(TrailingWhitespaceRegex) @lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 index = 0 for token in @tokens - if index < firstNonWhitespaceIndex - token.firstNonWhitespaceIndex = Math.min(index + token.value.length, firstNonWhitespaceIndex - index) + if index < @firstNonWhitespaceIndex + token.firstNonWhitespaceIndex = Math.min(index + token.value.length, @firstNonWhitespaceIndex - index) # Only the *last* segment of a soft-wrapped line can have trailing whitespace if @lineEnding? and (index + token.value.length > firstTrailingWhitespaceIndex) token.firstTrailingWhitespaceIndex = Math.max(0, firstTrailingWhitespaceIndex - index) From 61cc9b97eabb8f3c7d7e0dd8503768884f076a5d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:45:54 +0100 Subject: [PATCH 2/4] :green_heart: Fix failing spec --- spec/text-editor-component-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index f5c9e7677..20ddcdcab 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1937,14 +1937,14 @@ describe "TextEditorComponent", -> gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(11), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [19, 0]]] it "merges overlapping selections", -> gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(17), metaKey: true)) gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) nextAnimationFrame() gutterNode.dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenRowInGutter(9), metaKey: true)) - expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [19, 0]]] describe "when the gutter is shift-clicked and dragged", -> describe "when the shift-click is below the existing selection's tail", -> From 03b526a76b38984be939a9a87f6af3b09ae45761 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 11:48:10 +0100 Subject: [PATCH 3/4] :art: Use only @firstNonWhitespaceIndex --- src/tokenized-line.coffee | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 513ad5b4b..489714ae3 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -11,6 +11,7 @@ module.exports = class TokenizedLine endOfLineInvisibles: null lineIsWhitespaceOnly: false + firstNonWhitespaceIndex: 0 foldable: false constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @@ -162,12 +163,7 @@ class TokenizedLine @lineEnding is null isColumnOutsideIndentation: (column) -> - column >= @firstNonWhitespaceIndex and @isColumnOutsideSoftWrapIndentation(column) - - isColumnOutsideSoftWrapIndentation: (column) -> - return true if @softWrapIndentationTokens.length == 0 - - column > @softWrapIndentationDelta + column >= @firstNonWhitespaceIndex isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 From 0e0eeb34263fcb3d574614dc17701cec2eeba3b4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Mar 2015 12:23:10 +0100 Subject: [PATCH 4/4] :fire: Delete TokenizedLine#isColumnOutsideIndentation --- src/tokenized-line.coffee | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 489714ae3..b62ab316f 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -97,6 +97,7 @@ class TokenizedLine # Returns a {Number} representing the `line` position where the wrap would take place. # Returns `null` if a wrap wouldn't occur. findWrapColumn: (maxColumn) -> + return unless maxColumn? return unless @text.length > maxColumn if /\s/.test(@text[maxColumn]) @@ -107,7 +108,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..0] when @isColumnOutsideIndentation(column) + for column in [maxColumn..@firstNonWhitespaceIndex] return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -162,9 +163,6 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null - isColumnOutsideIndentation: (column) -> - column >= @firstNonWhitespaceIndex - isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0