diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 4fc0d1618..39d03330a 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -1113,3 +1113,30 @@ describe "TokenizedBuffer", -> expect(iterator.seek(Point(2, 0))).toEqual(["source.js"]) iterator.moveToSuccessor() # ensure we don't infinitely loop (regression test) + + it "does not report columns beyond the length of the line", -> + waitsForPromise -> + atom.packages.activatePackage('language-coffee-script') + + runs -> + buffer = new TextBuffer(text: "# hello\n# world") + tokenizedBuffer = new TokenizedBuffer({ + buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert + }) + tokenizedBuffer.setGrammar(atom.grammars.selectGrammar(".coffee")) + fullyTokenize(tokenizedBuffer) + + iterator = tokenizedBuffer.buildIterator() + iterator.seek(Point(0, 0)) + iterator.moveToSuccessor() + iterator.moveToSuccessor() + expect(iterator.getPosition().column).toBe(7) + + iterator.moveToSuccessor() + expect(iterator.getPosition().column).toBe(0) + + iterator.seek(Point(0, 7)) + expect(iterator.getPosition().column).toBe(7) + + iterator.seek(Point(0, 8)) + expect(iterator.getPosition().column).toBe(7) diff --git a/src/tokenized-buffer-iterator.coffee b/src/tokenized-buffer-iterator.coffee index acafb8f4b..e6e129d7a 100644 --- a/src/tokenized-buffer-iterator.coffee +++ b/src/tokenized-buffer-iterator.coffee @@ -14,6 +14,7 @@ class TokenizedBufferIterator currentLine = @tokenizedBuffer.tokenizedLineForRow(position.row) containingTags = currentLine.openScopes.map (id) => @grammarRegistry.scopeForId(id) @currentTags = currentLine.tags + @currentLineLength = currentLine.text.length currentColumn = 0 for tag, index in @currentTags if tag >= 0 @@ -32,39 +33,46 @@ class TokenizedBufferIterator @openTags.push(scopeName) @tagIndex ?= @currentTags.length - @position = Point(position.row, currentColumn) + @position = Point(position.row, Math.min(@currentLineLength, currentColumn)) containingTags moveToSuccessor: -> - if @tagIndex is @currentTags.length - @position = Point(@position.row + 1, 0) - @currentTags = @tokenizedBuffer.tokenizedLineForRow(@position.row)?.tags - return false unless @currentTags? - @tagIndex = 0 - else - @position = Point(@position.row, @position.column + @currentTags[@tagIndex]) - @tagIndex++ - @openTags = [] @closeTags = [] loop - tag = @currentTags[@tagIndex] - if tag >= 0 or @tagIndex is @currentTags.length + if @tagIndex is @currentTags.length if @isAtTagBoundary() break else - return @moveToSuccessor() + return false unless @moveToNextLine() else - scopeName = @grammarRegistry.scopeForId(tag) - if tag % 2 is 0 - @closeTags.push(scopeName) + tag = @currentTags[@tagIndex] + if tag >= 0 + if @isAtTagBoundary() + break + else + @position = Point(@position.row, Math.min(@currentLineLength, @position.column + @currentTags[@tagIndex])) else - @openTags.push(scopeName) - @tagIndex++ + scopeName = @grammarRegistry.scopeForId(tag) + if tag % 2 is 0 + @closeTags.push(scopeName) + else + @openTags.push(scopeName) + @tagIndex++ true + # Private + moveToNextLine: -> + @position = Point(@position.row + 1, 0) + tokenizedLine = @tokenizedBuffer.tokenizedLineForRow(@position.row) + return false unless tokenizedLine? + @currentTags = tokenizedLine.tags + @currentLineLength = tokenizedLine.text.length + @tagIndex = 0 + true + getPosition: -> @position