diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index bad30a506..db0229e9b 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1692,6 +1692,54 @@ describe('TreeSitterLanguageMode', () => { }) }) + describe('.commentStringsForPosition(position)', () => { + it('returns the correct comment strings for nested languages', () => { + const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { + scopeName: 'javascript', + parser: 'tree-sitter-javascript', + comments: {start: '//'}, + injectionRegExp: 'javascript', + injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] + }) + + const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + comments: {start: ''}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + }) + + atom.grammars.addGrammar(jsGrammar) + atom.grammars.addGrammar(htmlGrammar) + + const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + buffer.setLanguageMode(languageMode) + buffer.setText(` +
hi
+ + `.trim()) + + + const htmlCommentStrings = {commentStartString: ''} + const jsCommentStrings = {commentStartString: '//', commentEndString: undefined} + + expect(languageMode.commentStringsForPosition(new Point(0, 0))).toEqual(htmlCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(1, 0))).toEqual(htmlCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(2, 0))).toEqual(jsCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(3, 0))).toEqual(jsCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(4, 0))).toEqual(htmlCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(5, 0))).toEqual(jsCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual(htmlCommentStrings) + }) + }) + describe('TextEditor.selectLargerSyntaxNode and .selectSmallerSyntaxNode', () => { it('expands and contracts the selection based on the syntax tree', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { diff --git a/src/text-editor.js b/src/text-editor.js index 8b575d4eb..abdbb9c51 100644 --- a/src/text-editor.js +++ b/src/text-editor.js @@ -4768,7 +4768,7 @@ class TextEditor { const languageMode = this.buffer.getLanguageMode() let {commentStartString, commentEndString} = languageMode.commentStringsForPosition && - languageMode.commentStringsForPosition(Point(start, 0)) || {} + languageMode.commentStringsForPosition(new Point(start, 0)) || {} if (!commentStartString) return commentStartString = commentStartString.trim() diff --git a/src/tree-sitter-language-mode.js b/src/tree-sitter-language-mode.js index fc87f16ac..ae11274e7 100644 --- a/src/tree-sitter-language-mode.js +++ b/src/tree-sitter-language-mode.js @@ -144,17 +144,16 @@ class TreeSitterLanguageMode { Section - Commenting */ - commentStringsForPosition () { - return this.grammar.commentStrings + commentStringsForPosition (position) { + const range = this.firstNonWhitespaceRange(position.row) || new Range(position, position) + const {grammar} = this.getSyntaxNodeAndGrammarContainingRange(range) + return grammar.commentStrings } isRowCommented (row) { - const firstNonWhitespaceRange = this.buffer.findInRangeSync( - /\S/, - new Range(new Point(row, 0), new Point(row, Infinity)) - ) - if (firstNonWhitespaceRange) { - const firstNode = this.getSyntaxNodeContainingRange(firstNonWhitespaceRange) + const range = this.firstNonWhitespaceRange(row) + if (range) { + const firstNode = this.getSyntaxNodeContainingRange(range) if (firstNode) return firstNode.type.includes('comment') } return false @@ -367,23 +366,31 @@ class TreeSitterLanguageMode { */ getSyntaxNodeContainingRange (range, where = _ => true) { + return this.getSyntaxNodeAndGrammarContainingRange(range, where).node + } + + getSyntaxNodeAndGrammarContainingRange (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 + let smallestNode = null + let smallestNodeGrammar = this.grammar this._forEachTreeWithRange(range, (tree, grammar) => { let node = tree.rootNode.descendantForIndex(startIndex, searchEndIndex) while (node) { if (nodeContainsIndices(node, startIndex, endIndex) && where(node, grammar)) { - if (nodeIsSmaller(node, smallestNode)) smallestNode = node + if (nodeIsSmaller(node, smallestNode)) { + smallestNode = node + smallestNodeGrammar = grammar + } break } node = node.parent } }) - return smallestNode + return {node: smallestNode, grammar: smallestNodeGrammar} } getRangeForSyntaxNodeContainingRange (range, where) { @@ -482,6 +489,10 @@ class TreeSitterLanguageMode { Section - Private */ + firstNonWhitespaceRange (row) { + return this.buffer.findInRangeSync(/\S/, new Range(new Point(row, 0), new Point(row, Infinity))) + } + grammarForLanguageString (languageString) { return this.grammarRegistry.treeSitterGrammarForLanguageString(languageString) } @@ -599,7 +610,6 @@ class LanguageLayer { params.async = true tree = await tree } - tree.buffer = this.languageMode.buffer const changes = this.patchSinceCurrentParseStarted.getChanges() this.patchSinceCurrentParseStarted = null