🐎 Parse asynchronously when opening buffers

This commit is contained in:
Max Brunsfeld
2018-05-23 08:56:13 -07:00
parent 3548abe541
commit d4d57c2c8e
2 changed files with 41 additions and 18 deletions

View File

@@ -662,27 +662,35 @@ class Project extends Model {
// * `text` The {String} text to use as a buffer. // * `text` The {String} text to use as a buffer.
// //
// Returns a {Promise} that resolves to the {TextBuffer}. // Returns a {Promise} that resolves to the {TextBuffer}.
buildBuffer (absoluteFilePath) { async buildBuffer (absoluteFilePath) {
const params = {shouldDestroyOnFileDelete: this.shouldDestroyBufferOnFileDelete} const params = {shouldDestroyOnFileDelete: this.shouldDestroyBufferOnFileDelete}
let promise let buffer
if (absoluteFilePath != null) { if (absoluteFilePath != null) {
if (this.loadPromisesByPath[absoluteFilePath] == null) { if (this.loadPromisesByPath[absoluteFilePath] == null) {
this.loadPromisesByPath[absoluteFilePath] = this.loadPromisesByPath[absoluteFilePath] =
TextBuffer.load(absoluteFilePath, params).catch(error => { TextBuffer.load(absoluteFilePath, params)
delete this.loadPromisesByPath[absoluteFilePath] .then(result => {
throw error delete this.loadPromisesByPath[absoluteFilePath]
}) return result
})
.catch(error => {
delete this.loadPromisesByPath[absoluteFilePath]
throw error
})
} }
promise = this.loadPromisesByPath[absoluteFilePath] buffer = await this.loadPromisesByPath[absoluteFilePath]
} else { } else {
promise = Promise.resolve(new TextBuffer(params)) buffer = new TextBuffer(params)
} }
return promise.then(buffer => {
delete this.loadPromisesByPath[absoluteFilePath] this.grammarRegistry.autoAssignLanguageMode(buffer)
this.addBuffer(buffer) if (buffer.languageMode.initialize) {
return buffer await buffer.languageMode.initialize()
}) }
this.addBuffer(buffer)
return buffer
} }
addBuffer (buffer, options = {}) { addBuffer (buffer, options = {}) {

View File

@@ -16,7 +16,7 @@ class TreeSitterLanguageMode {
this.config = config this.config = config
this.parser = new Parser() this.parser = new Parser()
this.parser.setLanguage(grammar.languageModule) this.parser.setLanguage(grammar.languageModule)
this.tree = this.parser.parseTextBufferSync(this.buffer.buffer) this.tree = null
this.rootScopeDescriptor = new ScopeDescriptor({scopes: [this.grammar.id]}) this.rootScopeDescriptor = new ScopeDescriptor({scopes: [this.grammar.id]})
this.emitter = new Emitter() this.emitter = new Emitter()
this.isFoldableCache = [] this.isFoldableCache = []
@@ -35,11 +35,22 @@ class TreeSitterLanguageMode {
this.regexesByPattern = {} this.regexesByPattern = {}
} }
async initialize () {
this.tree = await this.parser.parseTextBuffer(this.buffer.buffer)
}
ensureParseTree () {
if (!this.tree) {
this.tree = this.parser.parseTextBufferSync(this.buffer.buffer)
}
}
getLanguageId () { getLanguageId () {
return this.grammar.id return this.grammar.id
} }
bufferDidChange (change) { bufferDidChange (change) {
this.ensureParseTree()
const {oldRange, newRange} = change const {oldRange, newRange} = change
const startRow = oldRange.start.row const startRow = oldRange.start.row
const oldEndRow = oldRange.end.row const oldEndRow = oldRange.end.row
@@ -93,7 +104,8 @@ class TreeSitterLanguageMode {
} }
buildHighlightIterator () { buildHighlightIterator () {
return new TreeSitterHighlightIterator(this) this.ensureParseTree()
return new TreeSitterHighlightIterator(this, this.tree.walk())
} }
onDidChangeHighlighting (callback) { onDidChangeHighlighting (callback) {
@@ -170,6 +182,7 @@ class TreeSitterLanguageMode {
} }
getFoldableRangesAtIndentLevel (goalLevel) { getFoldableRangesAtIndentLevel (goalLevel) {
this.ensureParseTree()
let result = [] let result = []
let stack = [{node: this.tree.rootNode, level: 0}] let stack = [{node: this.tree.rootNode, level: 0}]
while (stack.length > 0) { while (stack.length > 0) {
@@ -215,6 +228,7 @@ class TreeSitterLanguageMode {
} }
getFoldableRangeContainingPoint (point, tabLength, existenceOnly = false) { getFoldableRangeContainingPoint (point, tabLength, existenceOnly = false) {
this.ensureParseTree()
let node = this.tree.rootNode.descendantForPosition(this.buffer.clipPosition(point)) let node = this.tree.rootNode.descendantForPosition(this.buffer.clipPosition(point))
while (node) { while (node) {
if (existenceOnly && node.startPosition.row < point.row) break if (existenceOnly && node.startPosition.row < point.row) break
@@ -335,8 +349,8 @@ class TreeSitterLanguageMode {
} }
scopeDescriptorForPosition (point) { scopeDescriptorForPosition (point) {
this.ensureParseTree()
point = Point.fromObject(point) point = Point.fromObject(point)
const result = []
let node = this.tree.rootNode.descendantForPosition(point) let node = this.tree.rootNode.descendantForPosition(point)
// Don't include anonymous token types like '(' because they prevent scope chains // Don't include anonymous token types like '(' because they prevent scope chains
@@ -345,6 +359,7 @@ class TreeSitterLanguageMode {
// selectors. // selectors.
if (!node.isNamed) node = node.parent if (!node.isNamed) node = node.parent
const result = []
while (node) { while (node) {
result.push(node.type) result.push(node.type)
node = node.parent node = node.parent
@@ -363,9 +378,9 @@ class TreeSitterLanguageMode {
} }
class TreeSitterHighlightIterator { class TreeSitterHighlightIterator {
constructor (layer) { constructor (layer, treeCursor) {
this.layer = layer this.layer = layer
this.treeCursor = this.layer.tree.walk() this.treeCursor = treeCursor
// In order to determine which selectors match its current node, the iterator maintains // In order to determine which selectors match its current node, the iterator maintains
// a list of the current node's ancestors. Because the selectors can use the `:nth-child` // a list of the current node's ancestors. Because the selectors can use the `:nth-child`