From a8d01bcec1a8740966f5ee011fc33b05f9f0741c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 11 May 2015 23:35:52 +0200 Subject: [PATCH] Fix bufferRangeForScopeAtPosition with new tags array scheme --- spec/tokenized-buffer-spec.coffee | 4 +-- src/token.coffee | 2 +- src/tokenized-buffer.coffee | 57 +++++++++++++++++++++++-------- src/tokenized-line.coffee | 6 ---- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 768e77ba4..0c5363ad3 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -580,7 +580,7 @@ describe "TokenizedBuffer", -> describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual [[1, 6], [1, 28]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.meta.function', [1, 18])).toEqual [[1, 6], [1, 28]] describe "when the editor.tabLength config value changes", -> it "updates the tab length of the tokenized lines", -> @@ -734,7 +734,7 @@ describe "TokenizedBuffer", -> it "updates empty line indent guides when the empty line is the last line", -> buffer.insert([12, 2], '\n') - # The newline and he tab need to be in two different operations to surface the bug + # The newline and the tab need to be in two different operations to surface the bug buffer.insert([12, 0], ' ') expect(tokenizedBuffer.tokenizedLineForRow(13).indentLevel).toBe 1 diff --git a/src/token.coffee b/src/token.coffee index 583e25e9b..7b24764ae 100644 --- a/src/token.coffee +++ b/src/token.coffee @@ -24,7 +24,7 @@ class Token {@value, @scopes, @isAtomic, @bufferDelta, @isHardTab, @hasPairedCharacter, @isSoftWrapIndentation} = properties @firstNonWhitespaceIndex = properties.firstNonWhitespaceIndex ? null @firstTrailingWhitespaceIndex = properties.firstTrailingWhitespaceIndex ? null - + @screenDelta = @value.length @bufferDelta ?= @screenDelta @hasPairedCharacter ?= textUtils.hasPairedCharacter(@value) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 9dde39afe..b49f55939 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -1,6 +1,7 @@ _ = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' {Point, Range} = require 'text-buffer' +{ScopeSelector} = require 'first-mate' Serializable = require 'serializable' Model = require './model' TokenizedLine = require './tokenized-line' @@ -390,25 +391,53 @@ class TokenizedBuffer extends Model new Point(row, column) bufferRangeForScopeAtPosition: (selector, position) -> + selector = new ScopeSelector(selector.replace(/^\./, '')) position = Point.fromObject(position) - tokenizedLine = @tokenizedLines[position.row] - startIndex = tokenizedLine.tokenIndexAtBufferColumn(position.column) - for index in [startIndex..0] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - firstToken = token + {parentScopes, tags} = @tokenizedLines[position.row] + scopes = parentScopes.map (tag) -> atom.grammars.scopeForId(tag) - for index in [startIndex...tokenizedLine.getTokenCount()] - token = tokenizedLine.tokenAtIndex(index) - break unless token.matchesScopeSelector(selector) - lastToken = token + startColumn = 0 + for tag, tokenIndex in tags + if tag < 0 + if tag % 2 is -1 + scopes.push(atom.grammars.scopeForId(tag)) + else + scopes.pop() + else + endColumn = startColumn + tag + if endColumn > position.column + break + else + startColumn = endColumn - return unless firstToken? and lastToken? + return unless selector.matches(scopes) - startColumn = tokenizedLine.bufferColumnForToken(firstToken) - endColumn = tokenizedLine.bufferColumnForToken(lastToken) + lastToken.bufferDelta - new Range([position.row, startColumn], [position.row, endColumn]) + startScopes = scopes.slice() + for startTokenIndex in [(tokenIndex - 1)..0] by -1 + tag = tags[startTokenIndex] + if tag < 0 + if tag % 2 is -1 + startScopes.pop() + else + startScopes.push(atom.grammars.scopeForId(tag)) + else + break unless selector.matches(startScopes) + startColumn -= tag + + endScopes = scopes.slice() + for endTokenIndex in [(tokenIndex + 1)...tags.length] by 1 + tag = tags[endTokenIndex] + if tag < 0 + if tag % 2 is -1 + endScopes.push(atom.grammars.scopeForId(tag)) + else + endScopes.pop() + else + break unless selector.matches(endScopes) + endColumn += tag + + new Range(new Point(position.row, startColumn), new Point(position.row, endColumn)) iterateTokensInBufferRange: (bufferRange, iterator) -> bufferRange = Range.fromObject(bufferRange) diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index 063d2f6da..160c8360e 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -459,12 +459,6 @@ class TokenizedLine getTokenCount: -> @tokens.length - bufferColumnForToken: (targetToken) -> - column = 0 - for token in @tokens - return column if token is targetToken - column += token.bufferDelta - getScopeTree: -> return @scopeTree if @scopeTree?