Change TreeSitterLanguageMode::bufferRangeForScopeAtPosition(position) to

bufferRangeForScopeAtPosition(selector, position), to match the TextMateLanguageMode
signature, extracting some selector matching logic to do so.

Needed for https://github.com/atom/toggle-quotes/issues/57
This commit is contained in:
Ashi Krishnan
2018-07-20 16:22:15 -04:00
parent 643ffd6bb6
commit 176ee2a3b3
3 changed files with 51 additions and 12 deletions

42
src/selectors.js Normal file
View File

@@ -0,0 +1,42 @@
module.exports = {selectorMatchesAnyScope, matcherForSelector}
const _ = require('underscore-plus')
/**
* Parse a selector into parts. If already parsed, returns the selector
* unmodified.
*
* @param {String|Array<String>} selector
* @returns {Array<String>} selector parts
*/
function parse (selector) {
return typeof selector === 'string'
? selector.replace(/^\./, '').split('.')
: selector
}
const always = scope => true
/**
* Return a matcher function for a selector.
*
* @param {String} selector
* @returns {(scope: String) -> Boolean} a matcher function
*/
function matcherForSelector (selector) {
const parts = parse(selector)
return selector
? scope => _.isSubset(parts, parse(scope))
: always
}
/**
* Return true iff the selector matches any provided scope.
*
* @param {String} selector
* @param {Array<String>} scopes
* @returns {Boolean} true if any scope matches the selector
*/
function selectorMatchesAnyScope (selector, scopes) {
return !selector || scopes.some(matcherForSelector(selector))
}

View File

@@ -7,6 +7,7 @@ const ScopeDescriptor = require('./scope-descriptor')
const NullGrammar = require('./null-grammar')
const {OnigRegExp} = require('oniguruma')
const {toFirstMateScopeId, fromFirstMateScopeId} = require('./first-mate-helpers')
const {selectorMatchesAnyScope} = require('./selectors')
const NON_WHITESPACE_REGEX = /\S/
@@ -726,14 +727,6 @@ class TextMateLanguageMode {
TextMateLanguageMode.prototype.chunkSize = 50
function selectorMatchesAnyScope (selector, scopes) {
const targetClasses = selector.replace(/^\./, '').split('.')
return scopes.some((scope) => {
const scopeClasses = scope.split('.')
return _.isSubset(targetClasses, scopeClasses)
})
}
class TextMateHighlightIterator {
constructor (languageMode) {
this.languageMode = languageMode

View File

@@ -5,6 +5,7 @@ const {Emitter, Disposable} = require('event-kit')
const ScopeDescriptor = require('./scope-descriptor')
const TokenizedLine = require('./tokenized-line')
const TextMateLanguageMode = require('./text-mate-language-mode')
const {matcherForSelector} = require('./selectors')
let nextId = 0
const MAX_RANGE = new Range(Point.ZERO, Point.INFINITY).freeze()
@@ -348,25 +349,28 @@ class TreeSitterLanguageMode {
Section - Syntax Tree APIs
*/
getRangeForSyntaxNodeContainingRange (range) {
getRangeForSyntaxNodeContainingRange (range, selector) {
const startIndex = this.buffer.characterIndexForPosition(range.start)
const endIndex = this.buffer.characterIndexForPosition(range.end)
const searchEndIndex = Math.max(0, endIndex - 1)
const matches = matcherForSelector(selector)
let smallestNode
this._forEachTreeWithRange(range, tree => {
let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex)
while (node && !nodeContainsIndices(node, startIndex, endIndex)) {
node = node.parent
console.log(node)
}
if (nodeIsSmaller(node, smallestNode)) smallestNode = node
if (matches(node.type) && nodeIsSmaller(node, smallestNode)) smallestNode = node
})
if (smallestNode) return rangeForNode(smallestNode)
}
bufferRangeForScopeAtPosition (position) {
return this.getRangeForSyntaxNodeContainingRange(new Range(position, position))
bufferRangeForScopeAtPosition (selector, position) {
return this.getRangeForSyntaxNodeContainingRange(new Range(position, position), selector)
}
/*