Merge pull request #18438 from atom/mb-optimize-populate-injections

Optimize populating Tree-sitter syntax tree injections
This commit is contained in:
Max Brunsfeld
2018-11-14 15:34:31 -08:00
committed by GitHub
3 changed files with 65 additions and 18 deletions

View File

@@ -421,7 +421,11 @@ class GrammarRegistry {
addInjectionPoint (grammarId, injectionPoint) {
const grammar = this.treeSitterGrammarsById[grammarId]
if (grammar) {
grammar.injectionPoints.push(injectionPoint)
if (grammar.addInjectionPoint) {
grammar.addInjectionPoint(injectionPoint)
} else {
grammar.injectionPoints.push(injectionPoint)
}
} else {
this.treeSitterGrammarsById[grammarId] = {
injectionPoints: [injectionPoint]
@@ -429,8 +433,7 @@ class GrammarRegistry {
}
return new Disposable(() => {
const grammar = this.treeSitterGrammarsById[grammarId]
const index = grammar.injectionPoints.indexOf(injectionPoint)
if (index !== -1) grammar.injectionPoints.splice(index, 1)
grammar.removeInjectionPoint(injectionPoint)
})
}
@@ -454,7 +457,11 @@ class GrammarRegistry {
if (grammar instanceof TreeSitterGrammar) {
const existingParams = this.treeSitterGrammarsById[grammar.scopeName] || {}
if (grammar.scopeName) this.treeSitterGrammarsById[grammar.scopeName] = grammar
if (existingParams.injectionPoints) grammar.injectionPoints.push(...existingParams.injectionPoints)
if (existingParams.injectionPoints) {
for (const injectionPoint of existingParams.injectionPoints) {
grammar.addInjectionPoint(injectionPoint)
}
}
this.grammarAddedOrUpdated(grammar)
return new Disposable(() => this.removeGrammar(grammar))
} else {

View File

@@ -40,7 +40,11 @@ class TreeSitterGrammar {
this.scopeMap = new SyntaxScopeMap(scopeSelectors)
this.fileTypes = params.fileTypes || []
this.injectionPoints = params.injectionPoints || []
this.injectionPointsByType = {}
for (const injectionPoint of params.injectionPoints || []) {
this.addInjectionPoint(injectionPoint)
}
// TODO - When we upgrade to a new enough version of node, use `require.resolve`
// with the new `paths` option instead of this private API.
@@ -89,6 +93,25 @@ class TreeSitterGrammar {
deactivate () {
if (this.registration) this.registration.dispose()
}
addInjectionPoint (injectionPoint) {
let injectionPoints = this.injectionPointsByType[injectionPoint.type]
if (!injectionPoints) {
injectionPoints = this.injectionPointsByType[injectionPoint.type] = []
}
injectionPoints.push(injectionPoint)
}
removeInjectionPoint (injectionPoint) {
const injectionPoints = this.injectionPointsByType[injectionPoint.type]
if (injectionPoints) {
const index = injectionPoints.indexOf(injectionPoint)
if (index !== -1) injectionPoints.splice(index, 1)
if (injectionPoints.length === 0) {
delete this.injectionPointsByType[injectionPoint.type]
}
}
}
}
const preprocessScopes = value =>

View File

@@ -584,12 +584,12 @@ class LanguageLayer {
async update (nodeRangeSet) {
if (!this.currentParsePromise) {
do {
while (!this.destroyed && (!this.tree || this.tree.rootNode.hasChanges())) {
const params = {async: false}
this.currentParsePromise = this._performUpdate(nodeRangeSet, params)
if (!params.async) break
await this.currentParsePromise
} while (this.tree && this.tree.rootNode.hasChanges())
}
this.currentParsePromise = null
}
}
@@ -610,6 +610,7 @@ class LanguageLayer {
includedRanges = nodeRangeSet.getRanges()
if (includedRanges.length === 0) {
this.tree = null
this.destroyed = true
return
}
}
@@ -694,14 +695,15 @@ class LanguageLayer {
}
const markersToUpdate = new Map()
for (const injectionPoint of this.grammar.injectionPoints) {
const nodes = this.tree.rootNode.descendantsOfType(
injectionPoint.type,
range.start,
range.end
)
const nodes = this.tree.rootNode.descendantsOfType(
Object.keys(this.grammar.injectionPointsByType),
range.start,
range.end
)
for (const node of nodes) {
let existingInjectionMarkerIndex = 0
for (const node of nodes) {
for (const injectionPoint of this.grammar.injectionPointsByType[node.type]) {
const languageName = injectionPoint.language(node)
if (!languageName) continue
@@ -715,10 +717,25 @@ class LanguageLayer {
if (!injectionNodes.length) continue
const injectionRange = rangeForNode(node)
let marker = existingInjectionMarkers.find(m =>
m.getRange().isEqual(injectionRange) &&
m.languageLayer.grammar === grammar
)
let marker
for (let i = existingInjectionMarkerIndex, n = existingInjectionMarkers.length; i < n; i++) {
const existingMarker = existingInjectionMarkers[i]
const comparison = existingMarker.getRange().compare(injectionRange)
if (comparison > 0) {
break
} else if (comparison === 0) {
existingInjectionMarkerIndex = i
if (existingMarker.languageLayer.grammar === grammar) {
marker = existingMarker
marker.id === node.id
break
}
} else {
existingInjectionMarkerIndex = i
}
}
if (!marker) {
marker = this.languageMode.injectionsMarkerLayer.markRange(injectionRange)
marker.languageLayer = new LanguageLayer(this.languageMode, grammar, injectionPoint.contentChildTypes)