diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 58dae0241..7897e3ded 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -175,7 +175,6 @@ describe('TreeSitterLanguageMode', () => { ]) buffer.append(')') - await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ {text: 'a', scopes: ['function']}, @@ -459,6 +458,50 @@ describe('TreeSitterLanguageMode', () => { }) }) + describe('when changes are small enough to be re-parsed synchronously', () => { + it('can incorporate multiple consecutive synchronous updates', () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + parser: 'tree-sitter-javascript', + scopes: { + 'property_identifier': 'property', + 'call_expression > identifier': 'function', + 'call_expression > member_expression > property_identifier': 'method', + } + }) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + buffer.setLanguageMode(languageMode) + buffer.setText('a'); + expectTokensToEqual(editor, [[ + {text: 'a', scopes: []}, + ]]) + + buffer.append('.') + expectTokensToEqual(editor, [[ + {text: 'a.', scopes: []}, + ]]) + + buffer.append('b') + expectTokensToEqual(editor, [[ + {text: 'a.', scopes: []}, + {text: 'b', scopes: ['property']}, + ]]) + + buffer.append('()') + expectTokensToEqual(editor, [[ + {text: 'a.', scopes: []}, + {text: 'b', scopes: ['method']}, + {text: '()', scopes: []}, + ]]) + + buffer.delete([[0, 1], [0, 2]]) + expectTokensToEqual(editor, [[ + {text: 'ab', scopes: ['function']}, + {text: '()', scopes: []}, + ]]) + }) + }) + describe('injectionPoints and injectionPatterns', () => { let jsGrammar, htmlGrammar @@ -526,7 +569,6 @@ describe('TreeSitterLanguageMode', () => { const range = buffer.findSync('html') buffer.setTextInRange(range, 'xml') await nextHighlightingUpdate(languageMode) - await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 103b8816e..1e364605d 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -515,7 +515,9 @@ class LanguageLayer { async update (nodeRangeSet) { if (!this.currentParsePromise) { do { - this.currentParsePromise = this._performUpdate(nodeRangeSet) + 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 @@ -532,7 +534,7 @@ class LanguageLayer { } } - async _performUpdate (nodeRangeSet) { + async _performUpdate (nodeRangeSet, params) { let includedRanges = null if (nodeRangeSet) { includedRanges = nodeRangeSet.getRanges() @@ -551,7 +553,10 @@ class LanguageLayer { this.tree, includedRanges ) - if (tree.then) tree = await tree + if (tree.then) { + params.async = true + tree = await tree + } tree.buffer = this.languageMode.buffer const changes = this.patchSinceCurrentParseStarted.getChanges() @@ -590,7 +595,11 @@ class LanguageLayer { } } - await this._populateInjections(affectedRange, nodeRangeSet) + const injectionPromise = this._populateInjections(affectedRange, nodeRangeSet) + if (injectionPromise) { + params.async = true + return injectionPromise + } } _populateInjections (range, nodeRangeSet) { @@ -651,11 +660,14 @@ class LanguageLayer { } } - const promises = [] - for (const [marker, nodeRangeSet] of markersToUpdate) { - promises.push(marker.languageLayer.update(nodeRangeSet)) + if (markersToUpdate.size > 0) { + this.lastUpdateWasAsync = true + const promises = [] + for (const [marker, nodeRangeSet] of markersToUpdate) { + promises.push(marker.languageLayer.update(nodeRangeSet)) + } + return Promise.all(promises) } - return Promise.all(promises) } _treeEditForBufferChange (start, oldEnd, newEnd, oldText, newText) {