diff --git a/spec/display-buffer-spec.coffee b/spec/display-buffer-spec.coffee index 95f22acca..1703a24d1 100644 --- a/spec/display-buffer-spec.coffee +++ b/spec/display-buffer-spec.coffee @@ -115,24 +115,6 @@ 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/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 20ddcdcab..f5c9e7677 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], [19, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[7, 4], [7, 6]], [[10, 0], [20, 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], [19, 0]]] + expect(editor.getSelectedScreenRanges()).toEqual [[[5, 0], [20, 0]]] describe "when the gutter is shift-clicked and dragged", -> describe "when the shift-click is below the existing selection's tail", -> diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index b62ab316f..2a807d84a 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -11,7 +11,6 @@ module.exports = class TokenizedLine endOfLineInvisibles: null lineIsWhitespaceOnly: false - firstNonWhitespaceIndex: 0 foldable: false constructor: ({tokens, @lineEnding, @ruleStack, @startBufferColumn, @fold, @tabLength, @indentLevel, @invisibles}) -> @@ -97,7 +96,6 @@ 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]) @@ -108,7 +106,7 @@ class TokenizedLine return @text.length else # search backward for the start of the word on the boundary - for column in [maxColumn..@firstNonWhitespaceIndex] + for column in [maxColumn..0] when @isColumnOutsideSoftWrapIndentation(column) return column + 1 if /\s/.test(@text[column]) return maxColumn @@ -129,13 +127,12 @@ class TokenizedLine rightTokens = new Array(@tokens...) leftTokens = [] - leftScreenColumn = 0 - - while leftScreenColumn < column - if leftScreenColumn + rightTokens[0].screenDelta > column - rightTokens[0..0] = rightTokens[0].splitAt(column - leftScreenColumn) + leftTextLength = 0 + while leftTextLength < column + if leftTextLength + rightTokens[0].value.length > column + rightTokens[0..0] = rightTokens[0].splitAt(column - leftTextLength) nextToken = rightTokens.shift() - leftScreenColumn += nextToken.screenDelta + leftTextLength += nextToken.value.length leftTokens.push nextToken indentationTokens = @buildSoftWrapIndentationTokens(leftTokens[0], hangingIndent) @@ -163,6 +160,11 @@ class TokenizedLine isSoftWrapped: -> @lineEnding is null + isColumnOutsideSoftWrapIndentation: (column) -> + return true if @softWrapIndentationTokens.length == 0 + + column > @softWrapIndentationDelta + isColumnInsideSoftWrapIndentation: (column) -> return false if @softWrapIndentationTokens.length == 0 @@ -207,15 +209,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)