Incorporated injected languages in scope descriptors

This commit is contained in:
Max Brunsfeld
2018-07-16 13:43:10 -07:00
parent ebd546f572
commit 8fa9a45a54
2 changed files with 100 additions and 18 deletions

View File

@@ -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) }
}

View File

@@ -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
}