mirror of
https://github.com/atom/atom.git
synced 2026-01-26 07:19:06 -05:00
Incorporated injected languages in scope descriptors
This commit is contained in:
@@ -402,11 +402,7 @@ describe('TreeSitterLanguageMode', () => {
|
||||
attribute_name: 'attr'
|
||||
},
|
||||
injectionRegExp: 'html',
|
||||
injectionPoints: [{
|
||||
type: 'raw_element',
|
||||
language () { return 'javascript' },
|
||||
content (node) { return node.child(1) }
|
||||
}]
|
||||
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1081,6 +1077,61 @@ describe('TreeSitterLanguageMode', () => {
|
||||
'property_identifier'
|
||||
])
|
||||
})
|
||||
|
||||
it('includes nodes in injected syntax trees', async () => {
|
||||
const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, {
|
||||
id: 'javascript',
|
||||
parser: 'tree-sitter-javascript',
|
||||
scopes: {},
|
||||
injectionRegExp: 'javascript',
|
||||
injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT]
|
||||
})
|
||||
|
||||
const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, {
|
||||
id: 'html',
|
||||
parser: 'tree-sitter-html',
|
||||
scopes: {},
|
||||
injectionRegExp: 'html',
|
||||
injectionPoints: [SCRIPT_TAG_INJECTION_POINT]
|
||||
})
|
||||
|
||||
atom.grammars.addGrammar(jsGrammar)
|
||||
atom.grammars.addGrammar(htmlGrammar)
|
||||
|
||||
buffer.setText(`
|
||||
<div>
|
||||
<script>
|
||||
html \`
|
||||
<span>\${person.name}</span>
|
||||
\`
|
||||
</script>
|
||||
</div>
|
||||
`)
|
||||
|
||||
const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars})
|
||||
buffer.setLanguageMode(languageMode)
|
||||
await nextHighlightingUpdate(languageMode)
|
||||
await nextHighlightingUpdate(languageMode)
|
||||
await nextHighlightingUpdate(languageMode)
|
||||
|
||||
const position = buffer.findSync('name').start
|
||||
expect(languageMode.scopeDescriptorForPosition(position).getScopesArray()).toEqual([
|
||||
'html',
|
||||
'fragment',
|
||||
'element',
|
||||
'raw_element',
|
||||
'raw_text',
|
||||
'program',
|
||||
'expression_statement',
|
||||
'call_expression',
|
||||
'template_string',
|
||||
'fragment',
|
||||
'element',
|
||||
'template_substitution',
|
||||
'member_expression',
|
||||
'property_identifier'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('TextEditor.selectLargerSyntaxNode and .selectSmallerSyntaxNode', () => {
|
||||
@@ -1247,3 +1298,9 @@ const HTML_TEMPLATE_LITERAL_INJECTION_POINT = {
|
||||
return node.lastChild
|
||||
}
|
||||
}
|
||||
|
||||
const SCRIPT_TAG_INJECTION_POINT = {
|
||||
type: 'raw_element',
|
||||
language () { return 'javascript' },
|
||||
content (node) { return node.child(1) }
|
||||
}
|
||||
|
||||
@@ -389,23 +389,41 @@ class TreeSitterLanguageMode {
|
||||
|
||||
scopeDescriptorForPosition (point) {
|
||||
if (!this.tree) return this.rootScopeDescriptor
|
||||
|
||||
point = Point.fromObject(point)
|
||||
let node = this.tree.rootNode.descendantForPosition(point)
|
||||
|
||||
// Don't include anonymous token types like '(' because they prevent scope chains
|
||||
// from being parsed as CSS selectors by the `slick` parser. Other css selector
|
||||
// parsers like `postcss-selector-parser` do allow arbitrary quoted strings in
|
||||
// selectors.
|
||||
if (!node.isNamed) node = node.parent
|
||||
const iterators = []
|
||||
this._forEachTreeWithRange(new Range(point, point), tree => {
|
||||
const rootStartIndex = tree.rootNode.startIndex
|
||||
let node = tree.rootNode.descendantForPosition(point)
|
||||
|
||||
const result = []
|
||||
while (node) {
|
||||
result.push(node.type)
|
||||
node = node.parent
|
||||
// Don't include anonymous token types like '(' because they prevent scope chains
|
||||
// from being parsed as CSS selectors by the `slick` parser. Other css selector
|
||||
// parsers like `postcss-selector-parser` do allow arbitrary quoted strings in
|
||||
// selectors.
|
||||
if (!node.isNamed) node = node.parent
|
||||
iterators.push({node, rootStartIndex})
|
||||
})
|
||||
|
||||
iterators.sort(compareScopeDescriptorIterators)
|
||||
|
||||
const scopes = []
|
||||
for (;;) {
|
||||
const {length} = iterators
|
||||
if (!length) break
|
||||
const iterator = iterators[length - 1]
|
||||
scopes.push(iterator.node.type)
|
||||
iterator.node = iterator.node.parent
|
||||
if (iterator.node) {
|
||||
let i = length - 1
|
||||
while (i > 0 && compareScopeDescriptorIterators(iterator, iterators[i - 1]) < 0) i--
|
||||
if (i < length - 1) iterators.splice(i, 0, iterators.pop())
|
||||
} else {
|
||||
iterators.pop()
|
||||
}
|
||||
}
|
||||
result.push(this.grammar.id)
|
||||
return new ScopeDescriptor({scopes: result.reverse()})
|
||||
|
||||
scopes.push(this.grammar.id)
|
||||
return new ScopeDescriptor({scopes: scopes.reverse()})
|
||||
}
|
||||
|
||||
getGrammar () {
|
||||
@@ -1011,6 +1029,13 @@ function nodeIsSmaller (left, right) {
|
||||
return left.endIndex - left.startIndex < right.endIndex - right.startIndex
|
||||
}
|
||||
|
||||
function compareScopeDescriptorIterators (a, b) {
|
||||
return (
|
||||
a.node.startIndex - b.node.startIndex ||
|
||||
a.rootStartIndex - b.rootStartIndex
|
||||
)
|
||||
}
|
||||
|
||||
function pointIsGreater (left, right) {
|
||||
return left.row > right.row || left.row === right.row && left.column > right.column
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user