mirror of
https://github.com/atom/atom.git
synced 2026-01-25 14:59:03 -05:00
Accept a TextMate scope selector in bufferRangeForScopeAtPosition
This commit is contained in:
@@ -1504,20 +1504,21 @@ describe('TreeSitterLanguageMode', () => {
|
||||
it('returns the range of the smallest matching node at position', async () => {
|
||||
const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
|
||||
scopeName: 'javascript',
|
||||
parser: 'tree-sitter-javascript'
|
||||
parser: 'tree-sitter-javascript',
|
||||
scopes: {
|
||||
'property_identifier': 'variable.other.object.property',
|
||||
'template_string': 'string.quoted.template'
|
||||
}
|
||||
})
|
||||
|
||||
buffer.setText('foo({bar: baz});')
|
||||
buffer.setText('a(`${b({ccc: ddd})} eee`);')
|
||||
|
||||
buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar}))
|
||||
expect(editor.bufferRangeForScopeAtPosition('.property_identifier', [0, 6])).toEqual(
|
||||
buffer.findSync('bar')
|
||||
expect(editor.bufferRangeForScopeAtPosition('.variable.property', [0, 9])).toEqual(
|
||||
[[0, 8], [0, 11]]
|
||||
)
|
||||
expect(editor.bufferRangeForScopeAtPosition('.call_expression', [0, 6])).toEqual(
|
||||
[[0, 0], [0, buffer.getText().length - 1]]
|
||||
)
|
||||
expect(editor.bufferRangeForScopeAtPosition('.object', [0, 9])).toEqual(
|
||||
buffer.findSync('{bar: baz}')
|
||||
expect(editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6])).toEqual(
|
||||
[[0, 2], [0, 24]]
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1525,7 +1526,9 @@ describe('TreeSitterLanguageMode', () => {
|
||||
const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
|
||||
scopeName: 'javascript',
|
||||
parser: 'tree-sitter-javascript',
|
||||
scopes: {},
|
||||
scopes: {
|
||||
'property_identifier': 'variable.other.object.property',
|
||||
},
|
||||
injectionRegExp: 'javascript',
|
||||
injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT]
|
||||
})
|
||||
@@ -1533,7 +1536,9 @@ describe('TreeSitterLanguageMode', () => {
|
||||
const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, {
|
||||
scopeName: 'html',
|
||||
parser: 'tree-sitter-html',
|
||||
scopes: {},
|
||||
scopes: {
|
||||
'element': 'meta.element.html'
|
||||
},
|
||||
injectionRegExp: 'html',
|
||||
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
|
||||
})
|
||||
@@ -1557,9 +1562,9 @@ describe('TreeSitterLanguageMode', () => {
|
||||
const nameProperty = buffer.findSync('name')
|
||||
const {start} = nameProperty
|
||||
const position = Object.assign({}, start, {column: start.column + 2})
|
||||
expect(languageMode.bufferRangeForScopeAtPosition('.property_identifier', position))
|
||||
expect(languageMode.bufferRangeForScopeAtPosition('.object.property', position))
|
||||
.toEqual(nameProperty)
|
||||
expect(languageMode.bufferRangeForScopeAtPosition('.element', position))
|
||||
expect(languageMode.bufferRangeForScopeAtPosition('.meta.element.html', position))
|
||||
.toEqual(buffer.findSync('<span>\\${person\\.name}</span>'))
|
||||
})
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@ const parser = require('postcss-selector-parser')
|
||||
|
||||
module.exports =
|
||||
class SyntaxScopeMap {
|
||||
constructor (scopeNamesBySelector) {
|
||||
constructor (resultsBySelector) {
|
||||
this.namedScopeTable = {}
|
||||
this.anonymousScopeTable = {}
|
||||
for (let selector in scopeNamesBySelector) {
|
||||
this.addSelector(selector, scopeNamesBySelector[selector])
|
||||
for (let selector in resultsBySelector) {
|
||||
this.addSelector(selector, resultsBySelector[selector])
|
||||
}
|
||||
setTableDefaults(this.namedScopeTable)
|
||||
setTableDefaults(this.anonymousScopeTable)
|
||||
}
|
||||
|
||||
addSelector (selector, scopeName) {
|
||||
addSelector (selector, result) {
|
||||
parser((parseResult) => {
|
||||
for (let selectorNode of parseResult.nodes) {
|
||||
let currentTable = null
|
||||
@@ -91,7 +91,7 @@ class SyntaxScopeMap {
|
||||
}
|
||||
}
|
||||
|
||||
currentTable.scopeName = scopeName
|
||||
currentTable.result = result
|
||||
}
|
||||
}).process(selector)
|
||||
}
|
||||
@@ -110,8 +110,8 @@ class SyntaxScopeMap {
|
||||
currentTable = currentTable.indices[childIndices[i]]
|
||||
}
|
||||
|
||||
if (currentTable.scopeName) {
|
||||
result = currentTable.scopeName
|
||||
if (currentTable.result != null) {
|
||||
result = currentTable.result
|
||||
}
|
||||
|
||||
if (i === 0) break
|
||||
@@ -168,8 +168,8 @@ function mergeTable (table, defaultTable, mergeIndices = true) {
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultTable.scopeName && !table.scopeName) {
|
||||
table.scopeName = defaultTable.scopeName
|
||||
if (defaultTable.result != null && table.result == null) {
|
||||
table.result = defaultTable.result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class TreeSitterGrammar {
|
||||
|
||||
const scopeSelectors = {}
|
||||
for (const key in params.scopes || {}) {
|
||||
const classes = toSyntaxClasses(params.scopes[key])
|
||||
const classes = preprocessScopes(params.scopes[key])
|
||||
const selectors = key.split(/,\s+/)
|
||||
for (let selector of selectors) {
|
||||
selector = selector.trim()
|
||||
@@ -51,9 +51,9 @@ class TreeSitterGrammar {
|
||||
})
|
||||
|
||||
this.languageModule = require(languageModulePath)
|
||||
this.scopesById = new Map()
|
||||
this.conciseScopesById = new Map()
|
||||
this.idsByScope = {}
|
||||
this.classNamesById = new Map()
|
||||
this.scopeNamesById = new Map()
|
||||
this.idsByScope = Object.create(null)
|
||||
this.nextScopeId = 256 + 1
|
||||
this.registration = null
|
||||
}
|
||||
@@ -62,29 +62,24 @@ class TreeSitterGrammar {
|
||||
return `TreeSitterGrammar {scopeName: ${this.scopeName}}`
|
||||
}
|
||||
|
||||
idForScope (scope) {
|
||||
let id = this.idsByScope[scope]
|
||||
idForScope (scopeName) {
|
||||
let id = this.idsByScope[scopeName]
|
||||
if (!id) {
|
||||
id = this.nextScopeId += 2
|
||||
this.idsByScope[scope] = id
|
||||
this.scopesById.set(id, scope)
|
||||
const className = scopeName.split('.').map(s => `syntax--${s}`).join(' ')
|
||||
this.idsByScope[scopeName] = id
|
||||
this.classNamesById.set(id, className)
|
||||
this.scopeNamesById.set(id, scopeName)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
classNameForScopeId (id) {
|
||||
return this.scopesById.get(id)
|
||||
return this.classNamesById.get(id)
|
||||
}
|
||||
|
||||
scopeNameForScopeId (id) {
|
||||
let result = this.conciseScopesById.get(id)
|
||||
if (!result) {
|
||||
result = this.scopesById.get(id)
|
||||
.slice('syntax--'.length)
|
||||
.replace(/ syntax--/g, '.')
|
||||
this.conciseScopesById.set(id, result)
|
||||
}
|
||||
return result
|
||||
return this.scopeNamesById.get(id)
|
||||
}
|
||||
|
||||
activate () {
|
||||
@@ -96,17 +91,14 @@ class TreeSitterGrammar {
|
||||
}
|
||||
}
|
||||
|
||||
const toSyntaxClasses = scopes =>
|
||||
typeof scopes === 'string'
|
||||
? scopes
|
||||
.split('.')
|
||||
.map(s => `syntax--${s}`)
|
||||
.join(' ')
|
||||
: Array.isArray(scopes)
|
||||
? scopes.map(toSyntaxClasses)
|
||||
: scopes.match
|
||||
? {match: new RegExp(scopes.match), scopes: toSyntaxClasses(scopes.scopes)}
|
||||
: Object.assign({}, scopes, {scopes: toSyntaxClasses(scopes.scopes)})
|
||||
const preprocessScopes = value =>
|
||||
typeof value === 'string'
|
||||
? value
|
||||
: Array.isArray(value)
|
||||
? value.map(preprocessScopes)
|
||||
: value.match
|
||||
? {match: new RegExp(value.match), scopes: preprocessScopes(value.scopes)}
|
||||
: Object.assign({}, value, {scopes: preprocessScopes(value.scopes)})
|
||||
|
||||
const NODE_NAME_REGEX = /[\w_]+/
|
||||
|
||||
|
||||
@@ -372,10 +372,10 @@ class TreeSitterLanguageMode {
|
||||
const searchEndIndex = Math.max(0, endIndex - 1)
|
||||
|
||||
let smallestNode
|
||||
this._forEachTreeWithRange(range, tree => {
|
||||
this._forEachTreeWithRange(range, (tree, grammar) => {
|
||||
let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex)
|
||||
while (node) {
|
||||
if (nodeContainsIndices(node, startIndex, endIndex) && where(node)) {
|
||||
if (nodeContainsIndices(node, startIndex, endIndex) && where(node, grammar)) {
|
||||
if (nodeIsSmaller(node, smallestNode)) smallestNode = node
|
||||
break
|
||||
}
|
||||
@@ -396,9 +396,17 @@ class TreeSitterLanguageMode {
|
||||
}
|
||||
|
||||
bufferRangeForScopeAtPosition (selector, position) {
|
||||
const nodeCursorAdapter = new NodeCursorAdaptor()
|
||||
if (typeof selector === 'string') {
|
||||
const match = matcherForSelector(selector)
|
||||
selector = ({type}) => match(type)
|
||||
selector = (node, grammar) => {
|
||||
const rules = grammar.scopeMap.get([node.type], [0], node.named)
|
||||
nodeCursorAdapter.node = node
|
||||
const scopeName = applyLeafRules(rules, nodeCursorAdapter)
|
||||
if (scopeName != null) {
|
||||
return match(scopeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selector === null) selector = undefined
|
||||
const node = this.getSyntaxNodeAtPosition(position, selector)
|
||||
@@ -425,10 +433,10 @@ class TreeSitterLanguageMode {
|
||||
const iterator = this.buildHighlightIterator()
|
||||
const scopes = []
|
||||
for (const scope of iterator.seek(point)) {
|
||||
scopes.push(this.grammar.scopeNameForScopeId(scope, false))
|
||||
scopes.push(this.grammar.scopeNameForScopeId(scope))
|
||||
}
|
||||
for (const scope of iterator.getOpenScopeIds()) {
|
||||
scopes.push(this.grammar.scopeNameForScopeId(scope, false))
|
||||
scopes.push(this.grammar.scopeNameForScopeId(scope))
|
||||
}
|
||||
if (scopes.length === 0 || scopes[0] !== this.grammar.scopeName) {
|
||||
scopes.unshift(this.grammar.scopeName)
|
||||
@@ -743,14 +751,10 @@ class HighlightIterator {
|
||||
iterator.languageLayer.tree.rootNode.endPosition
|
||||
).toString()
|
||||
)
|
||||
console.log('close', iterator.closeTags.map(id => this.shortClassNameForScopeId(id)))
|
||||
console.log('open', iterator.openTags.map(id => this.shortClassNameForScopeId(id)))
|
||||
console.log('close', iterator.closeTags.map(id => this.languageMode.grammar.scopeNameForScopeId(id)))
|
||||
console.log('open', iterator.openTags.map(id => this.languageMode.grammar.scopeNameForScopeId(id)))
|
||||
}
|
||||
}
|
||||
|
||||
shortClassNameForScopeId (id) {
|
||||
return this.languageMode.classNameForScopeId(id).replace(/syntax--/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
class LayerHighlightIterator {
|
||||
@@ -944,14 +948,14 @@ class LayerHighlightIterator {
|
||||
}
|
||||
|
||||
_currentScopeId () {
|
||||
const rules = this.languageLayer.grammar.scopeMap.get(
|
||||
const value = this.languageLayer.grammar.scopeMap.get(
|
||||
this.containingNodeTypes,
|
||||
this.containingNodeChildIndices,
|
||||
this.treeCursor.nodeIsNamed
|
||||
)
|
||||
const scopes = applyLeafRules(rules, this.treeCursor)
|
||||
if (scopes) {
|
||||
return this.languageLayer.languageMode.grammar.idForScope(scopes)
|
||||
const scopeName = applyLeafRules(value, this.treeCursor)
|
||||
if (scopeName) {
|
||||
return this.languageLayer.languageMode.grammar.idForScope(scopeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -979,6 +983,12 @@ const applyLeafRules = (rules, cursor) => {
|
||||
}
|
||||
}
|
||||
|
||||
class NodeCursorAdaptor {
|
||||
get nodeText () {
|
||||
return this.node.text
|
||||
}
|
||||
}
|
||||
|
||||
class NullHighlightIterator {
|
||||
seek () { return [] }
|
||||
moveToSuccessor () {}
|
||||
|
||||
Reference in New Issue
Block a user