From 176ee2a3b3a167f68a82dafd153da09d940f20c0 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 16:22:15 -0400 Subject: [PATCH 01/10] Change TreeSitterLanguageMode::bufferRangeForScopeAtPosition(position) to bufferRangeForScopeAtPosition(selector, position), to match the TextMateLanguageMode signature, extracting some selector matching logic to do so. Needed for https://github.com/atom/toggle-quotes/issues/57 --- src/selectors.js | 42 ++++++++++++++++++++++++++++++++ src/text-mate-language-mode.js | 9 +------ src/tree-sitter-language-mode.js | 12 ++++++--- 3 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 src/selectors.js diff --git a/src/selectors.js b/src/selectors.js new file mode 100644 index 000000000..fc5d74cb1 --- /dev/null +++ b/src/selectors.js @@ -0,0 +1,42 @@ +module.exports = {selectorMatchesAnyScope, matcherForSelector} + +const _ = require('underscore-plus') + +/** + * Parse a selector into parts. If already parsed, returns the selector + * unmodified. + * + * @param {String|Array} selector + * @returns {Array} selector parts + */ +function parse (selector) { + return typeof selector === 'string' + ? selector.replace(/^\./, '').split('.') + : selector +} + +const always = scope => true + +/** + * Return a matcher function for a selector. + * + * @param {String} selector + * @returns {(scope: String) -> Boolean} a matcher function + */ +function matcherForSelector (selector) { + const parts = parse(selector) + return selector + ? scope => _.isSubset(parts, parse(scope)) + : always +} + +/** + * Return true iff the selector matches any provided scope. + * + * @param {String} selector + * @param {Array} scopes + * @returns {Boolean} true if any scope matches the selector + */ +function selectorMatchesAnyScope (selector, scopes) { + return !selector || scopes.some(matcherForSelector(selector)) +} diff --git a/src/text-mate-language-mode.js b/src/text-mate-language-mode.js index 9abe55ecb..471af9af2 100644 --- a/src/text-mate-language-mode.js +++ b/src/text-mate-language-mode.js @@ -7,6 +7,7 @@ const ScopeDescriptor = require('./scope-descriptor') const NullGrammar = require('./null-grammar') const {OnigRegExp} = require('oniguruma') const {toFirstMateScopeId, fromFirstMateScopeId} = require('./first-mate-helpers') +const {selectorMatchesAnyScope} = require('./selectors') const NON_WHITESPACE_REGEX = /\S/ @@ -726,14 +727,6 @@ class TextMateLanguageMode { TextMateLanguageMode.prototype.chunkSize = 50 -function selectorMatchesAnyScope (selector, scopes) { - const targetClasses = selector.replace(/^\./, '').split('.') - return scopes.some((scope) => { - const scopeClasses = scope.split('.') - return _.isSubset(targetClasses, scopeClasses) - }) -} - class TextMateHighlightIterator { constructor (languageMode) { this.languageMode = languageMode diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 7d0377f28..a9818b1ad 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -5,6 +5,7 @@ const {Emitter, Disposable} = require('event-kit') const ScopeDescriptor = require('./scope-descriptor') const TokenizedLine = require('./tokenized-line') const TextMateLanguageMode = require('./text-mate-language-mode') +const {matcherForSelector} = require('./selectors') let nextId = 0 const MAX_RANGE = new Range(Point.ZERO, Point.INFINITY).freeze() @@ -348,25 +349,28 @@ class TreeSitterLanguageMode { Section - Syntax Tree APIs */ - getRangeForSyntaxNodeContainingRange (range) { + getRangeForSyntaxNodeContainingRange (range, selector) { const startIndex = this.buffer.characterIndexForPosition(range.start) const endIndex = this.buffer.characterIndexForPosition(range.end) const searchEndIndex = Math.max(0, endIndex - 1) + const matches = matcherForSelector(selector) + let smallestNode this._forEachTreeWithRange(range, tree => { let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) while (node && !nodeContainsIndices(node, startIndex, endIndex)) { node = node.parent + console.log(node) } - if (nodeIsSmaller(node, smallestNode)) smallestNode = node + if (matches(node.type) && nodeIsSmaller(node, smallestNode)) smallestNode = node }) if (smallestNode) return rangeForNode(smallestNode) } - bufferRangeForScopeAtPosition (position) { - return this.getRangeForSyntaxNodeContainingRange(new Range(position, position)) + bufferRangeForScopeAtPosition (selector, position) { + return this.getRangeForSyntaxNodeContainingRange(new Range(position, position), selector) } /* From 6fe8b543505080dcbd47f555f26f45e371cb6302 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 18:16:22 -0400 Subject: [PATCH 02/10] Add tests and fix up the ascent query to find the smallest matching node. --- src/tree-sitter-language-mode.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index a9818b1ad..2d948c2ee 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -355,15 +355,17 @@ class TreeSitterLanguageMode { const searchEndIndex = Math.max(0, endIndex - 1) const matches = matcherForSelector(selector) - + let smallestNode this._forEachTreeWithRange(range, tree => { let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) - while (node && !nodeContainsIndices(node, startIndex, endIndex)) { - node = node.parent - console.log(node) + while (node) { + if (nodeContainsIndices(node, startIndex, endIndex) && matches(node.type)) { + if (nodeIsSmaller(node, smallestNode)) smallestNode = node + break + } + node = node.parent } - if (matches(node.type) && nodeIsSmaller(node, smallestNode)) smallestNode = node }) if (smallestNode) return rangeForNode(smallestNode) From 32c4624d95c2b9fa7997356a2f9b59e83ec99116 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 18:37:41 -0400 Subject: [PATCH 03/10] Add specs, clean up whitespace. --- src/tree-sitter-language-mode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 2d948c2ee..70555d1eb 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -355,7 +355,7 @@ class TreeSitterLanguageMode { const searchEndIndex = Math.max(0, endIndex - 1) const matches = matcherForSelector(selector) - + let smallestNode this._forEachTreeWithRange(range, tree => { let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) From be0565f3f4acfb9a50b1e9bb846e63327a1d3cf3 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 18:47:46 -0400 Subject: [PATCH 04/10] Convert to atom doc --- src/selectors.js | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/selectors.js b/src/selectors.js index fc5d74cb1..f6f415149 100644 --- a/src/selectors.js +++ b/src/selectors.js @@ -1,14 +1,12 @@ module.exports = {selectorMatchesAnyScope, matcherForSelector} -const _ = require('underscore-plus') +const {isSubset} = require('underscore-plus') -/** - * Parse a selector into parts. If already parsed, returns the selector - * unmodified. - * - * @param {String|Array} selector - * @returns {Array} selector parts - */ +// Private: Parse a selector into parts. +// If already parsed, returns the selector unmodified. +// +// * `selector` a {String|Array} specifying what to match +// Returns selector parts, an {Array}. function parse (selector) { return typeof selector === 'string' ? selector.replace(/^\./, '').split('.') @@ -17,26 +15,23 @@ function parse (selector) { const always = scope => true -/** - * Return a matcher function for a selector. - * - * @param {String} selector - * @returns {(scope: String) -> Boolean} a matcher function - */ +// Essential: Return a matcher function for a selector. +// +// * selector, a {String} selector +// Returns {(scope: String) -> Boolean}, a matcher function returning +// true iff the scope matches the selector. function matcherForSelector (selector) { const parts = parse(selector) return selector - ? scope => _.isSubset(parts, parse(scope)) + ? scope => isSubset(parts, parse(scope)) : always } -/** - * Return true iff the selector matches any provided scope. - * - * @param {String} selector - * @param {Array} scopes - * @returns {Boolean} true if any scope matches the selector - */ +// Essential: Return true iff the selector matches any provided scope. +// +// * {String} selector +// * {Array} scopes +// Returns {Boolean} true if any scope matches the selector. function selectorMatchesAnyScope (selector, scopes) { return !selector || scopes.some(matcherForSelector(selector)) } From 7cbd209811229568f64be65cbcdabea38368d68f Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 20:56:53 -0400 Subject: [PATCH 05/10] Allow a node matching function in bufferRangeForScopeAtPosition --- src/selectors.js | 1 + src/tree-sitter-language-mode.js | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/selectors.js b/src/selectors.js index f6f415149..3d4372e1e 100644 --- a/src/selectors.js +++ b/src/selectors.js @@ -22,6 +22,7 @@ const always = scope => true // true iff the scope matches the selector. function matcherForSelector (selector) { const parts = parse(selector) + if (typeof parts === 'function') return parts return selector ? scope => isSubset(parts, parse(scope)) : always diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index 70555d1eb..eac0c7894 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -349,18 +349,18 @@ class TreeSitterLanguageMode { Section - Syntax Tree APIs */ - getRangeForSyntaxNodeContainingRange (range, selector) { + getRangeForSyntaxNodeContainingRange (range, where = _ => true) { const startIndex = this.buffer.characterIndexForPosition(range.start) const endIndex = this.buffer.characterIndexForPosition(range.end) const searchEndIndex = Math.max(0, endIndex - 1) - const matches = matcherForSelector(selector) let smallestNode this._forEachTreeWithRange(range, tree => { + if (typeof selector === 'function') debugger let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) while (node) { - if (nodeContainsIndices(node, startIndex, endIndex) && matches(node.type)) { + if (nodeContainsIndices(node, startIndex, endIndex) && where(node)) { if (nodeIsSmaller(node, smallestNode)) smallestNode = node break } @@ -372,6 +372,11 @@ class TreeSitterLanguageMode { } bufferRangeForScopeAtPosition (selector, position) { + if (typeof selector === 'string') { + const match = matcherForSelector(selector) + selector = ({type}) => match(type) + } + if (selector === null) selector = undefined return this.getRangeForSyntaxNodeContainingRange(new Range(position, position), selector) } From 311b28a3a5b86b5bc061d30408f2919477fac2c8 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 21:16:59 -0400 Subject: [PATCH 06/10] Added getSyntaxNodeAtPosition and getSyntaxNodeContainingRange, tested --- src/tree-sitter-language-mode.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index eac0c7894..d60a57590 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -20,6 +20,13 @@ class TreeSitterLanguageMode { } }) } + if (!Parser.SyntaxNode.prototype.hasOwnProperty('range')) { + Object.defineProperty(Parser.SyntaxNode.prototype, 'range', { + get () { + return rangeForNode(this) + } + }) + } } constructor ({buffer, grammar, config, grammars}) { @@ -349,12 +356,11 @@ class TreeSitterLanguageMode { Section - Syntax Tree APIs */ - getRangeForSyntaxNodeContainingRange (range, where = _ => true) { + getSyntaxNodeContainingRange (range, where = _ => true) { const startIndex = this.buffer.characterIndexForPosition(range.start) const endIndex = this.buffer.characterIndexForPosition(range.end) const searchEndIndex = Math.max(0, endIndex - 1) - let smallestNode this._forEachTreeWithRange(range, tree => { if (typeof selector === 'function') debugger @@ -368,7 +374,11 @@ class TreeSitterLanguageMode { } }) - if (smallestNode) return rangeForNode(smallestNode) + return smallestNode + } + + getSyntaxNodeAtPosition (position, where) { + return this.getSyntaxNodeContainingRange(new Range(position, position), where) } bufferRangeForScopeAtPosition (selector, position) { @@ -377,7 +387,8 @@ class TreeSitterLanguageMode { selector = ({type}) => match(type) } if (selector === null) selector = undefined - return this.getRangeForSyntaxNodeContainingRange(new Range(position, position), selector) + const node = this.getSyntaxNodeAtPosition(position, selector) + return node && node.range } /* From 926cf73e63d4f2bdb61f7eec2357784d9332a2c3 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Fri, 20 Jul 2018 21:22:12 -0400 Subject: [PATCH 07/10] Tests for new query functions. --- spec/tree-sitter-language-mode-spec.js | 200 +++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index c23849d30..8886ab596 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1134,6 +1134,206 @@ describe('TreeSitterLanguageMode', () => { }) }) + describe('.bufferRangeForScopeAtPosition(selector?, position)', () => { + describe('when selector = null', () => { + it('returns the range of the smallest node at position', async () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + id: 'javascript', + parser: 'tree-sitter-javascript' + }) + + buffer.setText('foo({bar: baz});') + + buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + await nextHighlightingUpdate(buffer.getLanguageMode()) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual( + [[0, 5], [0, 8]] + ) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual( + [[0, 8], [0, 9]] + ) + }) + + 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(` +
+ +
+ `) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + buffer.setLanguageMode(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + + const nameProperty = buffer.findSync('name') + const {start} = nameProperty + const position = Object.assign({}, start, {column: start.column + 2}) + expect(languageMode.bufferRangeForScopeAtPosition(null, position)) + .toEqual(nameProperty) + }) + }) + + describe('with a selector', () => { + it('returns the range of the smallest matching node at position', async () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + id: 'javascript', + parser: 'tree-sitter-javascript' + }) + + buffer.setText('foo({bar: baz});') + + buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + await nextHighlightingUpdate(buffer.getLanguageMode()) + expect(editor.bufferRangeForScopeAtPosition('.property_identifier', [0, 6])).toEqual( + buffer.findSync('bar') + ) + expect(editor.bufferRangeForScopeAtPosition('.call_expression', [0, 6])).toEqual( + [[0, 0], [0, buffer.getText().length - 1]] + ) + expect(editor.bufferRangeForScopeAtPosition('.object', [0, 9])).toEqual( + buffer.findSync('{bar: baz}') + ) + }) + + 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(` +
+ +
+ `) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + buffer.setLanguageMode(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + + const nameProperty = buffer.findSync('name') + const {start} = nameProperty + const position = Object.assign({}, start, {column: start.column + 2}) + expect(languageMode.bufferRangeForScopeAtPosition('.property_identifier', position)) + .toEqual(nameProperty) + expect(languageMode.bufferRangeForScopeAtPosition('.element', position)) + .toEqual(buffer.findSync('\\${person\\.name}')) + }) + + it('accepts node-matching functions as selectors', 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(` +
+ +
+ `) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + buffer.setLanguageMode(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + await nextHighlightingUpdate(languageMode) + + const nameProperty = buffer.findSync('name') + const {start} = nameProperty + const position = Object.assign({}, start, {column: start.column + 2}) + const templateStringInCallExpression = node => + node.type === 'template_string' && node.parent.type === 'call_expression' + expect(languageMode.bufferRangeForScopeAtPosition(templateStringInCallExpression, position)) + .toEqual([[3, 19], [5, 15]]) + }) + }) + }) + + describe('.getSyntaxNodeAtPosition(position, where?)', () => { + fit('returns the range of the smallest matching node at position', async () => { + const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + id: 'javascript', + parser: 'tree-sitter-javascript' + }) + + buffer.setText('foo(bar({x: 2}));') + const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + buffer.setLanguageMode(languageMode) + await nextHighlightingUpdate(languageMode) + expect(languageMode.getSyntaxNodeAtPosition([0, 6]).range).toEqual( + buffer.findSync('bar') + ) + const findFoo = node => + node.type === 'call_expression' && node.firstChild.text === 'foo' + expect(languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range).toEqual( + [[0, 0], [0, buffer.getText().length - 1]] + ) + }) + }) + describe('TextEditor.selectLargerSyntaxNode and .selectSmallerSyntaxNode', () => { it('expands and contracts the selection based on the syntax tree', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { From 45ab5488ae6be7659a905481efec8a716bb8736c Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Mon, 23 Jul 2018 10:36:25 -0400 Subject: [PATCH 08/10] Remove debugger, test focus, and lint fixes. --- spec/tree-sitter-language-mode-spec.js | 2 +- src/selectors.js | 2 +- src/tree-sitter-language-mode.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 8886ab596..780641367 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1313,7 +1313,7 @@ describe('TreeSitterLanguageMode', () => { }) describe('.getSyntaxNodeAtPosition(position, where?)', () => { - fit('returns the range of the smallest matching node at position', async () => { + it('returns the range of the smallest matching node at position', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { id: 'javascript', parser: 'tree-sitter-javascript' diff --git a/src/selectors.js b/src/selectors.js index 3d4372e1e..ce03b80b4 100644 --- a/src/selectors.js +++ b/src/selectors.js @@ -4,7 +4,7 @@ const {isSubset} = require('underscore-plus') // Private: Parse a selector into parts. // If already parsed, returns the selector unmodified. -// +// // * `selector` a {String|Array} specifying what to match // Returns selector parts, an {Array}. function parse (selector) { diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index d60a57590..fda5679d1 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -363,14 +363,13 @@ class TreeSitterLanguageMode { let smallestNode this._forEachTreeWithRange(range, tree => { - if (typeof selector === 'function') debugger let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) while (node) { if (nodeContainsIndices(node, startIndex, endIndex) && where(node)) { if (nodeIsSmaller(node, smallestNode)) smallestNode = node break } - node = node.parent + node = node.parent } }) From d6ac437eb8c85d08f0e198953978f203231bafb6 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Mon, 23 Jul 2018 16:00:00 -0400 Subject: [PATCH 09/10] Restore getRangeForSyntaxNodeContainingRange to ensure selectLargerSyntaxNode and selectSmallerSyntaxNode keep working. --- src/tree-sitter-language-mode.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index fda5679d1..e23884a05 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -376,6 +376,11 @@ class TreeSitterLanguageMode { return smallestNode } + getRangeForSyntaxNodeContainingRange (range, where = _ => true) { + const node = this.getSyntaxNodeContainingRange(range, where) + return node && node.range + } + getSyntaxNodeAtPosition (position, where) { return this.getSyntaxNodeContainingRange(new Range(position, position), where) } From 8435d7edadde93201aec8a4953cd161b40fc1968 Mon Sep 17 00:00:00 2001 From: Ashi Krishnan Date: Tue, 24 Jul 2018 14:03:26 -0400 Subject: [PATCH 10/10] Update tree-sitter-language-mode.js Don't use a default predicate for `getRangeForSyntaxNodeContainingRange`. --- src/tree-sitter-language-mode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index e23884a05..139cc97c6 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -376,7 +376,7 @@ class TreeSitterLanguageMode { return smallestNode } - getRangeForSyntaxNodeContainingRange (range, where = _ => true) { + getRangeForSyntaxNodeContainingRange (range, where) { const node = this.getSyntaxNodeContainingRange(range, where) return node && node.range }