Merge pull request #677 from savetheclocktower/tree-sitter-more-fixes

Tree-sitter running fixes (August edition)
This commit is contained in:
Andrew Dupont 2023-09-13 15:14:27 -07:00 committed by GitHub
commit 69038a1c4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 612 additions and 168 deletions

View File

@ -12,7 +12,7 @@ const MAX_ROWS_TO_SCAN_BACKWARD_TRAVERSAL = Object.freeze(Point(-MAX_ROWS_TO_SCA
module.exports =
class BracketMatcherView {
constructor (editor, editorElement, matchManager) {
constructor(editor, editorElement, matchManager) {
this.destroy = this.destroy.bind(this)
this.updateMatch = this.updateMatch.bind(this)
this.editor = editor
@ -65,11 +65,11 @@ class BracketMatcherView {
this.updateMatch()
}
destroy () {
destroy() {
this.subscriptions.dispose()
}
updateMatch () {
updateMatch() {
if (this.pairHighlighted) {
this.editor.destroyMarker(this.startMarker.id)
this.editor.destroyMarker(this.endMarker.id)
@ -113,13 +113,13 @@ class BracketMatcherView {
this.tagHighlighted = highlightTag
}
selectMatchingBrackets () {
selectMatchingBrackets() {
if (!this.bracket1Range && !this.bracket2Range) return
this.editor.setSelectedBufferRanges([this.bracket1Range, this.bracket2Range])
this.matchManager.changeBracketsMode = true
}
removeMatchingBrackets () {
removeMatchingBrackets() {
if (this.editor.hasMultipleCursors()) {
this.editor.backspace()
return
@ -159,7 +159,7 @@ class BracketMatcherView {
})
}
findMatchingEndBracket (startBracketPosition, startBracket, endBracket) {
findMatchingEndBracket(startBracketPosition, startBracket, endBracket) {
if (startBracket === endBracket) return
if (this.hasSyntaxTree()) {
@ -171,7 +171,7 @@ class BracketMatcherView {
}
}
findMatchingStartBracket (endBracketPosition, startBracket, endBracket) {
findMatchingStartBracket(endBracketPosition, startBracket, endBracket) {
if (startBracket === endBracket) return
if (this.hasSyntaxTree()) {
@ -183,7 +183,7 @@ class BracketMatcherView {
}
}
findMatchingEndBracketWithSyntaxTree (bracketPosition, startBracket, endBracket) {
findMatchingEndBracketWithSyntaxTree(bracketPosition, startBracket, endBracket) {
let result
const bracketEndPosition = bracketPosition.traverse([0, startBracket.length])
this.editor.buffer.getLanguageMode().getSyntaxNodeContainingRange(
@ -202,7 +202,7 @@ class BracketMatcherView {
return result
}
findMatchingStartBracketWithSyntaxTree (bracketPosition, startBracket, endBracket) {
findMatchingStartBracketWithSyntaxTree(bracketPosition, startBracket, endBracket) {
let result
const bracketEndPosition = bracketPosition.traverse([0, startBracket.length])
this.editor.buffer.getLanguageMode().getSyntaxNodeContainingRange(
@ -221,7 +221,7 @@ class BracketMatcherView {
return result
}
findMatchingTagNameRangesWithSyntaxTree () {
findMatchingTagNameRangesWithSyntaxTree() {
const position = this.editor.getCursorBufferPosition()
const {startTag, endTag} = this.findContainingTagsWithSyntaxTree(position)
if (startTag && (startTag.range.containsPoint(position) || endTag.range.containsPoint(position))) {
@ -244,7 +244,7 @@ class BracketMatcherView {
}
}
findMatchingTagsWithSyntaxTree () {
findMatchingTagsWithSyntaxTree() {
const position = this.editor.getCursorBufferPosition()
const {startTag, endTag} = this.findContainingTagsWithSyntaxTree(position)
if (startTag) {
@ -254,7 +254,7 @@ class BracketMatcherView {
}
}
findContainingTagsWithSyntaxTree (position) {
findContainingTagsWithSyntaxTree(position) {
let startTag, endTag
if (position.column === this.editor.buffer.lineLengthForRow(position.row)) position.column--;
this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition(position, node => {
@ -275,14 +275,14 @@ class BracketMatcherView {
startTag = firstChild
endTag = lastChild
}
return true
}
return true
}
})
return {startTag, endTag}
}
findMatchingEndBracketWithRegexSearch (startBracketPosition, startBracket, endBracket) {
findMatchingEndBracketWithRegexSearch(startBracketPosition, startBracket, endBracket) {
const scanRange = new Range(
startBracketPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL),
startBracketPosition.traverse(MAX_ROWS_TO_SCAN_FORWARD_TRAVERSAL)
@ -308,7 +308,7 @@ class BracketMatcherView {
return endBracketPosition
}
findMatchingStartBracketWithRegexSearch (endBracketPosition, startBracket, endBracket) {
findMatchingStartBracketWithRegexSearch(endBracketPosition, startBracket, endBracket) {
const scanRange = new Range(
endBracketPosition.traverse(MAX_ROWS_TO_SCAN_BACKWARD_TRAVERSAL),
endBracketPosition
@ -334,7 +334,7 @@ class BracketMatcherView {
return startBracketPosition
}
findPrecedingStartBracket (cursorPosition) {
findPrecedingStartBracket(cursorPosition) {
if (this.hasSyntaxTree()) {
return this.findPrecedingStartBracketWithSyntaxTree(cursorPosition)
} else {
@ -342,7 +342,7 @@ class BracketMatcherView {
}
}
findPrecedingStartBracketWithSyntaxTree (cursorPosition) {
findPrecedingStartBracketWithSyntaxTree(cursorPosition) {
let result
this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition(cursorPosition, node => {
for (const child of node.children) {
@ -359,7 +359,7 @@ class BracketMatcherView {
return result
}
findPrecedingStartBracketWithRegexSearch (cursorPosition) {
findPrecedingStartBracketWithRegexSearch(cursorPosition) {
const scanRange = new Range(Point.ZERO, cursorPosition)
const startBracket = _.escapeRegExp(_.keys(this.matchManager.pairedCharacters).join(''))
const endBracket = _.escapeRegExp(_.keys(this.matchManager.pairedCharactersInverse).join(''))
@ -384,7 +384,7 @@ class BracketMatcherView {
return startPosition
}
createMarker (bufferRange) {
createMarker(bufferRange) {
const marker = this.editor.markBufferRange(bufferRange)
this.editor.decorateMarker(marker, {type: 'highlight', class: 'bracket-matcher', deprecatedRegionClass: 'bracket-matcher'})
if (atom.config.get('bracket-matcher.highlightMatchingLineNumber', {scope: this.editor.getRootScopeDescriptor()}) && this.gutter) {
@ -393,7 +393,7 @@ class BracketMatcherView {
return marker
}
findCurrentPair () {
findCurrentPair() {
const currentPosition = this.editor.getCursorBufferPosition()
const previousPosition = currentPosition.traverse(ONE_CHAR_BACKWARD_TRAVERSAL)
const nextPosition = currentPosition.traverse(ONE_CHAR_FORWARD_TRAVERSAL)
@ -422,7 +422,7 @@ class BracketMatcherView {
return {position, matchPosition, bracket: currentBracket}
}
goToMatchingBracket () {
goToMatchingBracket() {
if (!this.pairHighlighted) return this.gotoPrecedingStartBracket()
const position = this.editor.getCursorBufferPosition()
@ -468,7 +468,7 @@ class BracketMatcherView {
}
}
gotoPrecedingStartBracket () {
gotoPrecedingStartBracket() {
if (this.pairHighlighted) return
const matchPosition = this.findPrecedingStartBracket(this.editor.getCursorBufferPosition())
@ -522,7 +522,7 @@ class BracketMatcherView {
})
}
selectInsideBrackets () {
selectInsideBrackets() {
let endPosition, endRange, startPosition, startRange
if (this.pairHighlighted) {
startRange = this.startMarker.getBufferRange()
@ -550,7 +550,7 @@ class BracketMatcherView {
// Insert at the current cursor position a closing tag if there exists an
// open tag that is not closed afterwards.
closeTag () {
closeTag() {
const cursorPosition = this.editor.getCursorBufferPosition()
const preFragment = this.editor.getTextInBufferRange([Point.ZERO, cursorPosition])
const postFragment = this.editor.getTextInBufferRange([cursorPosition, Point.INFINITY])
@ -561,15 +561,15 @@ class BracketMatcherView {
}
}
isCursorOnCommentOrString () {
isCursorOnCommentOrString() {
return this.isScopeCommentedOrString(this.editor.getLastCursor().getScopeDescriptor().getScopesArray())
}
isRangeCommentedOrString (range) {
isRangeCommentedOrString(range) {
return this.isScopeCommentedOrString(this.editor.scopeDescriptorForBufferPosition(range.start).getScopesArray())
}
isScopeCommentedOrString (scopesArray) {
isScopeCommentedOrString(scopesArray) {
for (let scope of scopesArray.reverse()) {
scope = scope.split('.')
if (scope.includes('embedded') && scope.includes('source')) return false
@ -579,7 +579,7 @@ class BracketMatcherView {
return false
}
hasSyntaxTree () {
hasSyntaxTree() {
return this.editor.buffer.getLanguageMode().getSyntaxNodeAtPosition
}
}

View File

@ -46,6 +46,16 @@
(primitive_type) @storage.type.builtin.c
(type_identifier) @storage.type.other.c
; These types are all reserved words; if we see an identifier with this name,
; it must be a type.
((identifier) @storage.type.builtin.c
(#match? @storage.type.builtin.c "^(char|int|float|double|long)$"))
; Assume any identifier that ends in `_t` is a type. This convention is not
; always followed, but it's a very strong indicator when it's present.
((identifier) @storage.type.other.c
(#match? @storage.type.other.c "_t$"))
[
"enum"
"long"
@ -70,6 +80,10 @@
((primitive_type) @support.type.stdint.c
(#match? @support.type.stdint.c "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$"))
(enum_specifier
name: (type_identifier) @variable.other.declaration.type.c)
(type_definition
declarator: (_) @variable.other.declaration.type.c)
; CAVEAT: tree-sitter-c doesn't identify placeholders like `%c` in strings.
; Candidate for an injection grammar.
@ -111,19 +125,19 @@
declarator: (identifier) @variable.declaration.c)
(field_declaration
(field_identifier) @variable.declaration.c)
(field_identifier) @entity.other.attribute-name.c)
(field_declaration
(pointer_declarator
(field_identifier) @variable.declaration.c))
(field_identifier) @entity.other.attribute-name.c))
(field_declaration
(array_declarator
(field_identifier) @variable.declaration.c))
(field_identifier) @entity.other.attribute-name.c))
(init_declarator
(pointer_declarator
(identifier) @variable.declaration.c))
(identifier) @entity.other.attribute-name.c))
(assignment_expression
left: (identifier) @variable.other.assignment.c)
@ -158,7 +172,7 @@
; The "size" in `finfo->size`.
(field_expression
"->"
field: (field_identifier) @variable.other.member.c)
field: (field_identifier) @support.other.property.c)
; FUNCTIONS

View File

@ -1,2 +1,3 @@
((function_declarator (identifier) @name))
(function_declarator
(identifier) @name) @definition.function

View File

@ -58,6 +58,17 @@
(type_identifier) @storage.type.other.cpp
; (struct_specifier) @storage.type.cpp
; These types are all reserved words; if we see an identifier with this name,
; it must be a type.
((identifier) @storage.type.builtin.cpp
(#match? @storage.type.builtin.cpp "^(char|int|float|double|long)$"))
; Assume any identifier that ends in `_t` is a type. This convention is not
; always followed, but it's a very strong indicator when it's present.
((identifier) @storage.type.other.cpp
(#match? @storage.type.other.cpp "_t$"))
[
"enum"
"long"

View File

@ -1,2 +1,16 @@
((function_declarator (identifier) @name))
(function_declarator
(identifier) @name) @definition.function
(function_declarator
declarator: (qualified_identifier) @name) @definition.function
(class_specifier
name: (type_identifier) @name) @definition.class
(class_specifier
body: (field_declaration_list
(function_definition
declarator: (function_declarator
declarator: (field_identifier) @name)) @definition.method)
(#set! symbol.contextNode "parent.parent.parent.parent.firstNamedChild"))

View File

@ -156,7 +156,7 @@
; ------------------------
((plain_value) @support.constant.property-value.css
(#match? @support.constant.property-value.css "^(above|absolute|active|add|additive|after-edge|alias|all|all-petite-caps|all-scroll|all-small-caps|alpha|alphabetic|alternate|alternate-reverse|always|antialiased|auto|auto-pos|available|avoid|avoid-column|avoid-page|avoid-region|backwards|balance|baseline|before-edge|below|bevel|bidi-override|blink|block|block-axis|block-start|block-end|bold|bolder|border|border-box|both|bottom|bottom-outside|break-all|break-word|bullets|butt|capitalize|caption|cell|center|central|char|circle|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color|color-burn|color-dodge|column|column-reverse|common-ligatures|compact|condensed|contain|content|content-box|contents|context-menu|contextual|copy|cover|crisp-edges|crispEdges|crosshair|cyclic|dark|darken|dashed|decimal|default|dense|diagonal-fractions|difference|digits|disabled|disc|discretionary-ligatures|distribute|distribute-all-lines|distribute-letter|distribute-space|dot|dotted|double|double-circle|downleft|downright|e-resize|each-line|ease|ease-in|ease-in-out|ease-out|economy|ellipse|ellipsis|embed|end|evenodd|ew-resize|exact|exclude|exclusion|expanded|extends|extra-condensed|extra-expanded|fallback|farthest-corner|farthest-side|fill|fill-available|fill-box|filled|fit-content|fixed|flat|flex|flex-end|flex-start|flip|flow-root|forwards|freeze|from-image|full-width|geometricPrecision|georgian|grab|grabbing|grayscale|grid|groove|hand|hanging|hard-light|help|hidden|hide|historical-forms|historical-ligatures|horizontal|horizontal-tb|hue|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|infinite|inherit|initial|inline|inline-axis|inline-block|inline-end|inline-flex|inline-grid|inline-list-item|inline-start|inline-table|inset|inside|inter-character|inter-ideograph|inter-word|intersect|invert|isolate|isolate-override|italic|jis04|jis78|jis83|jis90|justify|justify-all|kannada|keep-all|landscape|large|larger|left|light|lighten|lighter|line|line-edge|line-through|linear|linearRGB|lining-nums|list-item|local|loose|lowercase|lr|lr-tb|ltr|luminance|luminosity|main-size|mandatory|manipulation|manual|margin-box|match-parent|match-source|mathematical|max-content|medium|menu|message-box|middle|min-content|miter|mixed|move|multiply|n-resize|narrower|ne-resize|nearest-neighbor|nesw-resize|newspaper|no-change|no-clip|no-close-quote|no-common-ligatures|no-contextual|no-discretionary-ligatures|no-drop|no-historical-ligatures|no-open-quote|no-repeat|none|nonzero|normal|not-allowed|nowrap|ns-resize|numbers|numeric|nw-resize|nwse-resize|oblique|oldstyle-nums|open|open-quote|optimizeLegibility|optimizeQuality|optimizeSpeed|optional|ordinal|outset|outside|over|overlay|overline|padding|padding-box|page|painted|pan-down|pan-left|pan-right|pan-up|pan-x|pan-y|paused|petite-caps|pixelated|plaintext|pointer|portrait|pre|pre-line|pre-wrap|preserve-3d|progress|progressive|proportional-nums|proportional-width|proximity|radial|recto|region|relative|remove|repeat|repeat-[xy]|reset-size|reverse|revert|ridge|right|rl|rl-tb|round|row|row-resize|row-reverse|row-severse|rtl|ruby|ruby-base|ruby-base-container|ruby-text|ruby-text-container|run-in|running|s-resize|saturation|scale-down|screen|scroll|scroll-position|se-resize|semi-condensed|semi-expanded|separate|sesame|show|sideways|sideways-left|sideways-lr|sideways-right|sideways-rl|simplified|slashed-zero|slice|small|small-caps|small-caption|smaller|smooth|soft-light|solid|space|space-around|space-between|space-evenly|spell-out|square|sRGB|stacked-fractions|start|static|status-bar|swap|step-end|step-start|sticky|stretch|strict|stroke|stroke-box|style|sub|subgrid|subpixel-antialiased|subtract|super|sw-resize|symbolic|table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row|table-row-group|tabular-nums|tb|tb-rl|text|text-after-edge|text-before-edge|text-bottom|text-top|thick|thin|titling-caps|top|top-outside|touch|traditional|transparent|triangle|ultra-condensed|ultra-expanded|under|underline|unicase|unset|upleft|uppercase|upright|use-glyph-orientation|use-script|verso|vertical|vertical-ideographic|vertical-lr|vertical-rl|vertical-text|view-box|visible|visibleFill|visiblePainted|visibleStroke|w-resize|wait|wavy|weight|whitespace|wider|words|wrap|wrap-reverse|x|x-large|x-small|xx-large|xx-small|y|zero|zoom-in|zoom-out)$"))
(#match? @support.constant.property-value.css "^(above|absolute|active|add|additive|after-edge|alias|all|all-petite-caps|all-scroll|all-small-caps|alpha|alphabetic|alternate|alternate-reverse|always|antialiased|auto|auto-pos|available|avoid|avoid-column|avoid-page|avoid-region|backwards|balance|baseline|before-edge|below|bevel|bidi-override|blink|block|block-axis|block-start|block-end|bold|bolder|border|border-box|both|bottom|bottom-outside|break-all|break-word|bullets|butt|capitalize|caption|cell|center|central|char|circle|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color|color-burn|color-dodge|column|column-reverse|common-ligatures|compact|condensed|contain|content|content-box|contents|context-menu|contextual|copy|cover|crisp-edges|crispEdges|crosshair|cyclic|dark|darken|dashed|decimal|default|dense|diagonal-fractions|difference|digits|disabled|disc|discretionary-ligatures|distribute|distribute-all-lines|distribute-letter|distribute-space|dot|dotted|double|double-circle|downleft|downright|e-resize|each-line|ease|ease-in|ease-in-out|ease-out|economy|ellipse|ellipsis|embed|end|evenodd|ew-resize|exact|exclude|exclusion|expanded|extends|extra-condensed|extra-expanded|fallback|farthest-corner|farthest-side|fill|fill-available|fill-box|filled|fit-content|fixed|flat|flex|flex-end|flex-start|flip|flow-root|forwards|freeze|from-image|full-width|geometricPrecision|georgian|grab|grabbing|grayscale|grid|groove|hand|hanging|hard-light|help|hidden|hide|historical-forms|historical-ligatures|horizontal|horizontal-tb|hue|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|ideographic|inactive|infinite|inherit|initial|inline|inline-axis|inline-block|inline-end|inline-flex|inline-grid|inline-list-item|inline-size|inline-start|inline-table|inset|inside|inter-character|inter-ideograph|inter-word|intersect|invert|isolate|isolate-override|italic|jis04|jis78|jis83|jis90|justify|justify-all|kannada|keep-all|landscape|large|larger|layout|left|light|lighten|lighter|line|line-edge|line-through|linear|linearRGB|lining-nums|list-item|local|loose|lowercase|lr|lr-tb|ltr|luminance|luminosity|main-size|mandatory|manipulation|manual|margin-box|match-parent|match-source|mathematical|max-content|medium|menu|message-box|middle|min-content|miter|mixed|move|multiply|n-resize|narrower|ne-resize|nearest-neighbor|nesw-resize|newspaper|no-change|no-clip|no-close-quote|no-common-ligatures|no-contextual|no-discretionary-ligatures|no-drop|no-historical-ligatures|no-open-quote|no-repeat|none|nonzero|normal|not-allowed|nowrap|ns-resize|numbers|numeric|nw-resize|nwse-resize|oblique|oldstyle-nums|open|open-quote|optimizeLegibility|optimizeQuality|optimizeSpeed|optional|ordinal|outset|outside|over|overlay|overline|padding|padding-box|page|paint|painted|pan-down|pan-left|pan-right|pan-up|pan-x|pan-y|paused|petite-caps|pixelated|plaintext|pointer|portrait|pre|pre-line|pre-wrap|preserve-3d|progress|progressive|proportional-nums|proportional-width|proximity|radial|recto|region|relative|remove|repeat|repeat-[xy]|reset-size|reverse|revert|ridge|right|rl|rl-tb|round|row|row-resize|row-reverse|row-severse|rtl|ruby|ruby-base|ruby-base-container|ruby-text|ruby-text-container|run-in|running|s-resize|saturation|scale-down|screen|scroll|scroll-position|se-resize|semi-condensed|semi-expanded|separate|sesame|show|sideways|sideways-left|sideways-lr|sideways-right|sideways-rl|simplified|size|slashed-zero|slice|small|small-caps|small-caption|smaller|smooth|soft-light|solid|space|space-around|space-between|space-evenly|spell-out|square|sRGB|stacked-fractions|start|static|status-bar|swap|step-end|step-start|sticky|stretch|strict|stroke|stroke-box|style|sub|subgrid|subpixel-antialiased|subtract|super|sw-resize|symbolic|table|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row|table-row-group|tabular-nums|tb|tb-rl|text|text-after-edge|text-before-edge|text-bottom|text-top|thick|thin|titling-caps|top|top-outside|touch|traditional|transparent|triangle|ultra-condensed|ultra-expanded|under|underline|unicase|unset|upleft|uppercase|upright|use-glyph-orientation|use-script|verso|vertical|vertical-ideographic|vertical-lr|vertical-rl|vertical-text|view-box|visible|visibleFill|visiblePainted|visibleStroke|w-resize|wait|wavy|weight|whitespace|wider|words|wrap|wrap-reverse|x|x-large|x-small|xx-large|xx-small|y|zero|zoom-in|zoom-out)$"))
; All property values that have special meaning in `font-family`.
; TODO: Restrict these to be meaningful only when the property name is font-related?

View File

@ -3,15 +3,23 @@
(switch_body)
(class_body)
(object)
(formal_parameters)
(template_string)
(named_imports)
] @fold
((arguments) @fold
; When we've got
;
; function foo(
; bar,
; baz,
; thud
; )
;
; we want to be able to fold up the group of function parameters while
; preserving the ability to collapse the function body.
([(arguments) (formal_parameters)] @fold
(#set! fold.adjustToEndOfPreviousRow true))
; When we've got
;
; if (foo) {
@ -32,7 +40,7 @@
((comment) @fold
(#set! fold.endAt endPosition)
(#set! fold.adjustEndColumn 0))
(#set! fold.offsetEnd -2))
; When you have…

View File

@ -543,10 +543,18 @@
(#match? @punctuation.definition.comment.js "^\/\/")
(#set! adjust.startAndEndAroundFirstMatchOf "^\/\/"))
((comment) @comment.block.documentation.js
(#match? @comment.block.documentation.js "^/\\*\\*")
(#set! capture.final true)
(#set! highlight.invalidateOnChange true))
; Block comments. `/* */`
((comment) @comment.block.js
(#match? @comment.block.js "^/\\*")
(#match? @comment.block.js "\\*/$"))
(#match? @comment.block.js "\\*/$")
(#set! highlight.invalidateOnChange true))
((comment) @punctuation.definition.comment.begin.js
(#match? @punctuation.definition.comment.begin.js "^/\\*")
@ -888,29 +896,43 @@
; The interiors of functions (useful for snippets and commands).
(method_definition
body: (statement_block) @meta.block.function.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition)
(#set! capture.final true))
(function_declaration
body: (statement_block) @meta.block.function.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition)
(#set! capture.final true))
(generator_function_declaration
body: (statement_block) @meta.block.function.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition)
(#set! capture.final true))
(function
body: (statement_block) @meta.block.function.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition)
(#set! capture.final true))
(generator_function
body: (statement_block) @meta.block.function.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition)
(#set! capture.final true))
; The interior of a class body (useful for snippets and commands).
(class_body) @meta.block.class.js
((class_body) @meta.block.class.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))
; All other sorts of blocks.
(statement_block) @meta.block.js
((statement_block) @meta.block.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))
; The inside of a parameter definition list.
((formal_parameters) @meta.parameters.js
@ -923,6 +945,20 @@
(#set! adjust.endAt lastChild.startPosition))
([
(jsx_opening_element)
(jsx_closing_element)
] @meta.jsx.inside-tag.js
(#set! adjust.startAt firstChild.endPosition))
((jsx_self_closing_element) @meta.jsx.inside-tag.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))
((jsx_element) @meta.block.jsx.js
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))
; MISC
; ====

View File

@ -94,23 +94,25 @@
; =============================
; TODO: We might want to make this configurable behavior with the
; `Config` scope test.
; `config` scope test.
; Any of these at the end of a line indicate the next line should be indented…
(["||" "&&" "?"] @indent
(#is? test.lastTextOnRow true))
; …and the line after that should be dedented.
; …and the line after that should be dedented
(binary_expression
["||" "&&"]
right: (_) @dedent.next
(#is-not? test.startsOnSameRowAs parent.startPosition))
; …unless it's a ternary, in which case the dedent should wait until the
; alternative clause.
;
; let foo = this.longTernaryCondition() ?
; consequenceWhichIsItselfRatherLong :
; alternativeThatIsNotBrief;
;
; …followed by a dedent.
(ternary_expression
alternative: (_) @dedent.next
(#is-not? test.startsOnSameRowAs parent.startPosition))
@ -153,5 +155,8 @@
; JSX
; ===
(jsx_opening_element ">") @indent
(jsx_closing_element ">") @dedent
(jsx_opening_element ["<" ">"] @indent)
(jsx_opening_element [">"] @dedent)
(jsx_closing_element ">" @dedent)

View File

@ -19,6 +19,7 @@
((document) @punctuation.definition.end.comment.js.jsdoc
(#set! adjust.startAndEndAroundFirstMatchOf "(?:\\*)?\\*/$"))
((inline_tag) @meta.inline-tag.js.jsdoc)
(tag_name) @storage.type.class.jsdoc

View File

@ -2,8 +2,10 @@
(comment)* @doc
.
(method_definition
name: (property_identifier) @name) @definition.method
(#not-eq? @name "constructor")
name: (property_identifier) @name
(#set! symbol.contextNode "parent.parent.parent.firstNamedChild")
) @definition.method
; (#not-eq? @name "constructor")
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.method)
)
@ -22,19 +24,6 @@
name: (_) @name) @definition.class
)
; (
; (comment)* @doc
; .
; [
; (class
; name: (_) @name)
; (class_declaration
; name: (_) @name)
; ] @definition.class
; (#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
; (#select-adjacent! @doc @definition.class)
; )
(
(comment)* @doc
.
@ -87,19 +76,19 @@
key: (property_identifier) @name
value: [(arrow_function) (function)]) @definition.function
; (
; (call_expression
; function: (identifier) @name) @reference.call
; (#not-match? @name "^(require)$")
; )
;
; (call_expression
; function: (member_expression
; property: (property_identifier) @name)
; arguments: (_) @reference.call)
;
; (new_expression
; constructor: (_) @name) @reference.class
(
(call_expression
function: (identifier) @name) @reference.call
(#not-match? @name "^(require)$")
)
(call_expression
function: (member_expression
property: (property_identifier) @name)
arguments: (_)) @reference.call
(new_expression
constructor: (_) @name) @reference.class
(export_statement value: (assignment_expression left: (identifier) @name right: ([
(number)

View File

@ -1,4 +1,4 @@
exports.activate = function() {
exports.activate = function () {
if (!atom.grammars.addInjectionPoint) return;
atom.grammars.addInjectionPoint('source.js', {
@ -70,41 +70,38 @@ exports.activate = function() {
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
const HYPERLINK_PATTERN = /\bhttps?:/
for (const scopeName of ['source.js', 'source.ts', 'source.ts.tsx']) {
atom.grammars.addInjectionPoint(scopeName, {
type: 'comment',
language(comment) {
if (comment.text.startsWith('/**')) return 'jsdoc';
},
content(comment) {
return comment;
},
languageScope: null,
coverShallowerScopes: true
});
atom.grammars.addInjectionPoint('source.js', {
type: 'comment',
language(comment) {
if (comment.text.startsWith('/**')) return 'jsdoc';
},
content(comment) {
return comment;
},
languageScope: null,
coverShallowerScopes: true
});
// Experiment: better to have one layer with lots of nodes, or lots of
// layers each managing one node?
atom.grammars.addInjectionPoint(scopeName, {
type: 'comment',
// Experiment: better to have one layer with lots of nodes, or lots of
// layers each managing one node?
atom.grammars.addInjectionPoint('source.js', {
type: 'comment',
language: (node) => {
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
},
content: (node) => node,
languageScope: null
});
for (let type of ['template_string', 'string_fragment', 'comment']) {
atom.grammars.addInjectionPoint('source.js', {
type,
language: (node) => {
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
},
content: (node) => node,
languageScope: null
});
for (let type of ['template_string', 'string_fragment', 'comment']) {
atom.grammars.addInjectionPoint(scopeName, {
type,
language: (node) => {
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
},
content: (node) => node,
languageScope: null
});
}
}
};

View File

@ -11,3 +11,13 @@
'decreaseIndentPattern': '(?x)
^ \\s* (\\s* /[*] .* [*]/ \\s*)* [}\\])]
'
'.source.js .meta.block.jsx.js':
'editor':
'commentStart': '{/*'
'commentEnd': '*/}'
'.source.js .meta.jsx.inside-tag.js':
'editor':
'commentStart': '{/*'
'commentEnd': '*/}'

View File

@ -128,3 +128,18 @@
'return':
'prefix': 'ret'
'body': 'return $1;$0'
'.source.js .meta.block.function.js':
'Function':
'prefix': 'fun'
'body': 'function ${1:functionName}($2) {\n\t$0\n}'
'.source.js .meta.block.class.js':
'Function':
'prefix': 'fun'
'body': '${1:functionName}($2) {\n\t$0\n}'
'.source.js .meta.object.js':
'Function':
'prefix': 'fun'
'body': '${1:functionName}($2) {\n\t$0\n},'

View File

@ -4,6 +4,7 @@
; Nested keys try to prepend the symbol name of their parent's key.
(pair key: (string (string_content) @name
(#is-not? test.descendantOfType "array")
(#set! symbol.tag "property")
(#set! symbol.prependSymbolForNode parent.parent.parent.previousNamedSibling.firstNamedChild)
(#set! symbol.contextNode parent.parent.parent.previousNamedSibling.firstNamedChild)
(#set! symbol.joiner ".")))

View File

@ -3,8 +3,6 @@
; * No support for lookbehind as of March 2023 (waiting on
; https://github.com/tree-sitter/tree-sitter-regex/pull/15)
(pattern) @string.regexp
(non_capturing_group) @meta.group.non-capturing.regexp
[

View File

@ -1,4 +1,4 @@
exports.activate = function() {
exports.activate = function () {
if (!atom.grammars.addInjectionPoint) return;
atom.grammars.addInjectionPoint('source.ruby', {
@ -19,6 +19,7 @@ exports.activate = function() {
content(node) {
return node;
},
languageScope: null,
includeChildren: true,
// coverShallowerScopes: false
});

View File

@ -0,0 +1,25 @@
exports.activate = () => {
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
const HYPERLINK_PATTERN = /\bhttps?:/
atom.grammars.addInjectionPoint('source.shell', {
type: 'comment',
language: (node) => {
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
},
content: (node) => node,
languageScope: null
});
atom.grammars.addInjectionPoint('source.shell', {
type: 'comment',
language(node) {
return HYPERLINK_PATTERN.test(node.text) ?
'hyperlink' : undefined;
},
content: (node) => node,
languageScope: null
});
};

View File

@ -1,13 +1,14 @@
{
"name": "language-shellscript",
"version": "0.28.2",
"main": "lib/main",
"description": "ShellScript language support in Atom",
"keywords": [
"tree-sitter"
],
"engines": {
"atom": "*",
"node": "*"
"node": ">=12"
},
"repository": "https://github.com/pulsar-edit/pulsar",
"license": "MIT",

View File

@ -2,15 +2,23 @@
(switch_body)
(class_body)
(object)
(formal_parameters)
(template_string)
(named_imports)
] @fold
((arguments) @fold
; When we've got
;
; function foo(
; bar,
; baz,
; thud
; )
;
; we want to be able to fold up the group of function parameters while
; preserving the ability to collapse the function body.
([(arguments) (formal_parameters)] @fold
(#set! fold.adjustToEndOfPreviousRow true))
; When we've got
;
; if (foo) {
@ -31,4 +39,4 @@
((comment) @fold
(#set! fold.endAt endPosition)
(#set! fold.adjustEndColumn 0))
(#set! fold.offsetEnd -2))

View File

@ -9,6 +9,10 @@
(import_specifier
(identifier) @variable.other.assignment.import._LANG_)
; The "foo" in `import * as foo from './bar'`
(namespace_import
(identifier) @variable.other.assignment.import.namespace._LANG_)
; The "Foo" in `export { Foo }`
(export_specifier
name: (identifier) @variable.other.assignment.export._LANG_)
@ -37,8 +41,19 @@
(#match? @punctuation.definition.comment._LANG_ "^//")
(#set! adjust.startAndEndAroundFirstMatchOf "^//"))
((comment) @comment.block.documentation._LANG_
(#match? @comment.block.documentation._LANG_ "^/\\*\\*")
(#set! capture.final true)
(#set! highlight.invalidateOnChange true))
; Block comments. `/* */`
((comment) @comment.block._LANG_
(#match? @comment.block._LANG_ "^/\\*"))
(#match? @comment.block._LANG_ "^/\\*")
(#match? @comment.block._LANG_ "\\*/$")
(#set! highlight.invalidateOnChange true))
; ((comment) @comment.block._LANG_
; (#match? @comment.block._LANG_ "^/\\*"))
((comment) @punctuation.definition.comment.begin._LANG_
(#match? @punctuation.definition.comment.begin._LANG_ "^/\\*")
@ -65,7 +80,8 @@
; =======
(class_declaration
name: (type_identifier) @entity.name.type.class._LANG_)
name: (type_identifier) @entity.name.type.class._LANG_
(#set! capture.final true))
(extends_clause
value: (_) @entity.other.inherited-class._LANG_)
@ -90,12 +106,27 @@
"set" @storage.setter._LANG_)
; NAMESPACES
; ==========
(internal_module
name: (identifier) @entity.name.type.namespace._LANG_)
; DECLARATIONS
; ============
(function_signature
name: (identifier) @entity.name.function.signature._LANG_)
; INTERFACES
; ==========
(interface_declaration
name: (_) @entity.name.type.interface._LANG_)
; TYPES
; =====
@ -178,6 +209,8 @@
(property_signature
(property_identifier) @entity.other.attribute-name._LANG_)
; FUNCTIONS
; =========
@ -259,6 +292,10 @@
(required_parameter
pattern: (identifier) @variable.parameter._LANG_)
(required_parameter
pattern: (rest_pattern
(identifier) @variable.parameter.rest._LANG_))
(required_parameter
pattern: (object_pattern
(shorthand_property_identifier_pattern) @variable.parameter.destructuring._LANG_)
@ -269,6 +306,9 @@
(optional_parameter "?" @keyword.operator.type.optional._LANG_)
(type_predicate
name: (identifier) @variable.other.type._LANG_
"is" @keyword.operator.type.is._LANG_)
["var" "const" "let"] @storage.type._TYPE_._LANG_
@ -306,7 +346,16 @@
(pair_pattern
; TODO: This arguably isn't an object key.
key: (_) @entity.other.attribute-name._LANG_
value: (identifier) @variable.other.assignment.destructuring._LANG_))
value: (identifier) @variable.other.assignment.destructuring._LANG_)
(#set! capture.final true))
; A complex object alias destructuring:
; The "bar" in `let { bar: { foo: troz } } = something`
(object_pattern
(pair_pattern
; TODO: This arguably isn't an object key.
key: (_) @entity.other.attribute-name._LANG_)
(#set! capture.final true))
; A variable object alias destructuring with default value:
; The "bar" and "foo" in `let { bar: foo = true } = something`

View File

@ -1,14 +1,124 @@
; The closing brace of a switch statement's body should match the indentation of the line where the switch statement starts.
; STATEMENT BLOCKS
; ================
; More accurate indentation matching for all blocks delimited by braces.
(statement_block "}" @match
(#set! indent.matchIndentOf parent.firstChild.startPosition))
; SWITCH STATEMENTS
; =================
; The closing brace of a switch statement's body should match the indentation
; of the line where the switch statement starts.
(switch_statement
body: (switch_body "}" @match
(#is? test.last true))
(#set! indent.matchIndentOf parent.parent.startPosition))
(#set! indent.matchIndentOf parent.startPosition))
; 'case' and 'default' need to be indented one level more than their containing
; `switch`.
(["case" "default"] @match
(#set! indent.matchIndentOf parent.parent.startPosition)
(#set! indent.offsetIndent 1))
; `switch`. TODO: Might need to make this configurable.
(["case" "default"] @match
(#set! indent.matchIndentOf parent.parent.startPosition)
(#set! indent.offsetIndent 1))
; ONE-LINE CONDITIONALS
; =====================
; An `if` statement without an opening brace should indent the next line…
(if_statement
condition: (parenthesized_expression ")" @indent
(#is? test.lastTextOnRow true)))
; (as should a braceless `else`…)
("else" @indent
(#is? test.lastTextOnRow true))
; …and keep that indent level if the user types a comment before the
; consequence…
(if_statement
consequence: (empty_statement) @match
(#is-not? test.startsOnSameRowAs parent.startPosition)
(#set! indent.matchIndentOf parent.startPosition)
(#set! indent.offsetIndent 1))
; …and keep that indent level after the user starts typing…
(if_statement
condition: (_) @indent
consequence: [
(expression_statement)
(return_statement)
(continue_statement)
(break_statement)
(throw_statement)
(debugger_statement)
] @match
; When an opening curly brace is unpaired, it might get interpreted as part
; of an `expression_statement`, for some reason.
(#not-match? @match "^\\s*{")
(#set! indent.matchIndentOf parent.startPosition)
(#set! indent.offsetIndent 1))
; …but dedent after exactly one statement.
(if_statement
condition: (_) @indent
consequence: [
(expression_statement)
(return_statement)
(continue_statement)
(break_statement)
(throw_statement)
(debugger_statement)
] @dedent.next
; When an opening curly brace is unpaired, it might get interpreted as part
; of an `expression_statement`, for some reason.
(#not-match? @dedent.next "^\\s*{"))
(else_clause
[
(expression_statement)
(return_statement)
(continue_statement)
(break_statement)
(throw_statement)
(debugger_statement)
] @dedent.next
(#is-not? test.startsOnSameRowAs parent.startPosition))
; HANGING INDENT ON SPLIT LINES
; =============================
; TODO: We might want to make this configurable behavior with the
; `config` scope test.
; Any of these at the end of a line indicate the next line should be indented…
(["||" "&&" "?"] @indent
(#is? test.lastTextOnRow true))
; …and the line after that should be dedented.
(binary_expression
["||" "&&"]
right: (_) @dedent.next
(#is-not? test.startsOnSameRowAs parent.startPosition))
; …unless it's a ternary, in which case the dedent should wait until the
; alternative clause.
;
; let foo = this.longTernaryCondition() ?
; consequenceWhichIsItselfRatherLong :
; alternativeThatIsNotBrief;
;
(ternary_expression
alternative: (_) @dedent.next
(#is-not? test.startsOnSameRowAs parent.startPosition))
; GENERAL
; =======
; Weed out `}`s that should not signal dedents.
(template_substitution "}" @_IGNORE_ (#set! capture.final true))
[
"{"
@ -27,5 +137,4 @@
(type_arguments "<" @indent)
(type_arguments ">" @dedent)
["case" "default"] @indent

View File

@ -38,3 +38,21 @@
(#set! adjust.startAt lastChild.previousSibling.startPosition)
(#set! adjust.endAt lastChild.endPosition)
(#set! capture.final true))
; META
; ====
([
(jsx_opening_element)
(jsx_closing_element)
] @meta.jsx.inside-tag.ts.tsx
(#set! adjust.startAt firstChild.endPosition))
((jsx_self_closing_element) @meta.jsx.inside-tag.ts.tsx
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))
((jsx_element) @meta.block.jsx.ts.tsx
(#set! adjust.startAt firstChild.endPosition)
(#set! adjust.endAt lastChild.startPosition))

View File

@ -2,5 +2,7 @@
; JSX
; ===
(jsx_opening_element) @indent
(jsx_closing_element ">") @dedent
(jsx_opening_element ["<" ">"] @indent)
(jsx_opening_element [">"] @dedent)
(jsx_closing_element ">" @dedent)

View File

@ -1,5 +1,17 @@
exports.activate = function() {
exports.activate = function () {
for (const scopeName of ['source.ts', 'source.tsx', 'source.flow']) {
atom.grammars.addInjectionPoint(scopeName, {
type: 'comment',
language(comment) {
if (comment.text.startsWith('/**')) return 'jsdoc';
},
content(comment) {
return comment;
},
languageScope: null,
// coverShallowerScopes: true
});
atom.grammars.addInjectionPoint(scopeName, {
type: 'call_expression',
@ -53,9 +65,31 @@ exports.activate = function() {
},
languageScope: null
});
atom.grammars.addInjectionPoint(scopeName, {
type: 'comment',
language: (node) => {
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
},
content: (node) => node,
languageScope: null
});
for (let type of ['template_string', 'string_fragment', 'comment']) {
atom.grammars.addInjectionPoint(scopeName, {
type,
language: (node) => {
return HYPERLINK_PATTERN.test(node.text) ? 'hyperlink' : undefined;
},
content: (node) => node,
languageScope: null
});
}
}
};
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
const HYPERLINK_PATTERN = /\bhttps?:/
const STYLED_REGEX = /\bstyled\b/i;
function languageStringForTemplateTag(tag) {

View File

@ -11,9 +11,9 @@
^ \\s* (\\s* /[*] .* [*]/ \\s*)* [}\\])]
'
'.meta.tag.tsx':
'.meta.tag.tsx, .meta.block.jsx.ts.tsx':
'editor':
'commentStart': '{/* ',
'commentEnd': ' */}',
'increaseIndentPattern': "{[^}\"']*$|\\[[^\\]\"']*$|\\([^)\"']*$|<[a-zA-Z][^/]*$|^\\s*>$",
'decreaseIndentPattern': "^\\s*(\\s*/[*].*[*]/\\s*)*[}\\])]|^\\s*(</|/>)"
'decreaseIndentPattern': "^\\s*(\\s*/[*].*[*]/\\s*)*[}\\])]|^\\s*(</|/>)"

View File

@ -4,11 +4,11 @@
(block_mapping_pair
key: (_) @entity.name.tag.yaml
(#set! test.final true))
(#set! capture.final true))
(flow_pair
key: (_) @entity.name.tag.yaml
(#set! test.final true))
(#set! capture.final true))
; COMMENTS
@ -35,6 +35,14 @@
((string_scalar) @string.quoted.yaml)
(single_quote_scalar) @string.quoted.single.yaml
((single_quote_scalar) @punctuation.definition.string.begin.yaml
(#set! adjust.endAfterFirstMatchOf "^'"))
((single_quote_scalar) @punctuation.definition.string.end.yaml
(#set! adjust.startBeforeFirstMatchOf "'$"))
(double_quote_scalar) @string.quoted.double.yaml
((double_quote_scalar) @punctuation.definition.string.begin.yaml

View File

@ -1,4 +1,4 @@
(":" @indent
(#set! test.onlyIfLastTextOnRow true))
(#is? test.lastTextOnRow true))
["|" ">"] @indent

View File

@ -1,6 +1,6 @@
(block_mapping_pair
key: (_) @name
(#set! test.final true)
(#set! capture.final true)
(#set! symbol.prependSymbolForNode parent.parent.parent.parent.parent.parent.parent.firstNamedChild)
(#set! symbol.joiner "."))

View File

@ -228,7 +228,7 @@ describe('ScopeResolver', () => {
let bar = "this is a line below a comment"
`);
// Prevent an exception from being thrown before we can even check the
// scopeResovler.
// scopeResolver.
spyOn(languageMode, 'isRowCommented').andReturn(false);
await languageMode.ready;

View File

@ -16,6 +16,11 @@ function comparePoints(a, b) {
}
}
function rangeSpecToString (range) {
let [sp, ep] = [range.startPosition, range.endPosition];
return `(${sp.row}, ${sp.column}) - (${ep.row}, ${ep.column})`;
}
function resolveNodeDescriptor(node, descriptor) {
let parts = descriptor.split('.');
let result = node;
@ -266,6 +271,20 @@ class ScopeResolver {
return ScopeResolver.CAPTURE_SETTINGS[prop](...args);
}
warnAboutExceededRange(range, capture) {
let msg = ['Cannot extend past original range of capture!'];
msg.push(`Scope name: ${capture.name}`);
msg.push(`Original range: ${rangeSpecToString(capture.node)}`);
msg.push(`Adjusted range: ${rangeSpecToString(range)}`);
if (atom.inDevMode()) {
throw new Error(msg.join('\n'));
}
console.warn(msg.join('\n'));
}
// Given a capture and possible predicate data, determines the buffer range
// that this capture wants to cover.
determineCaptureRange(capture) {
@ -299,7 +318,7 @@ class ScopeResolver {
}
if (this.rangeExceedsBoundsOfCapture(range, capture)) {
throw new Error('Cannot extend past original range of capture');
this.warnAboutExceededRange(range, capture);
}
// Any invalidity in the returned range means we shouldn't store this

View File

@ -45,6 +45,8 @@ module.exports = class WASMTreeSitterGrammar {
commentEndString: params.comments && params.comments.end
};
this.commentMetadata = params.comments;
this.shouldObserveQueryFiles = atom.inDevMode() && !atom.inSpecMode();
this.getLanguage();
@ -69,6 +71,50 @@ module.exports = class WASMTreeSitterGrammar {
return id;
}
// Retrieve the comment delimiters for this grammar.
//
// Traditionally, grammars specified only the delimiters needed for the
// “Toggle Line Comments” command — either a line comment (if it existed) or
// a block comment. But other features might want to know _all_ of a
// language's possible comment delimiters, so we've devised new config values.
getCommentDelimiters() {
let meta = this.commentMetadata;
if (!meta) { return null; }
let result = {};
// The new convention is to specify a `line` property and start/end
// properties.
let { line, block } = this.commentMetadata;
// Failing that, we can deliver at least a partial result by inspecting the
// older convention. If `start` exists but not `end`, we know `start` must
// be a line comment delimiter.
if (!line && meta.start && !meta.end) {
line = meta.start;
}
// Likewise, if both `start` and `end` exist, we know they must be block
// comment delimiters.
if (!block && meta.start && meta.end) {
block = { start: meta.start, end: meta.end };
}
// Strip all whitespace from delimiters. Whatever is consuming them can
// decide if it wants whitespace.
if (line) {
line = line.strip();
result.line = line;
}
if (block) {
block.start = block.start?.strip();
block.end = block.end?.strip();
result.block = block;
}
return result;
}
classNameForScopeId(id) {
return this.classNamesById.get(id);
}
@ -127,7 +173,7 @@ module.exports = class WASMTreeSitterGrammar {
this.observeQueryFile(filePaths, key);
}
}
Promise.all(promises).then(() => resolve());
return Promise.all(promises).then(() => resolve());
}).then(() => {
this._queryFilesLoaded = true;
this._loadQueryFilesPromise = null;
@ -254,7 +300,9 @@ module.exports = class WASMTreeSitterGrammar {
await this.getLanguage();
this.queryCache.delete(queryType);
this[queryType] = contents;
return await this.getQuery(queryType);
let query = await this.getQuery(queryType);
this.emitter.emit('did-change-query-file', { filePath: '', queryType });
return query;
}
// Observe a particular query file on disk so that it can immediately be

View File

@ -1056,19 +1056,42 @@ class WASMTreeSitterLanguageMode {
Section - Comments
*/
// TODO: I know that old tree-sitter moved toward placing this data on the
// grammar itself, but I would prefer to invert the order of these lookups.
// As a config setting it can be scoped and overridden, but as a grammar
// property it's just a fact of life that can't be worked around.
//
// TODO: Also, this should be revisited soon so that we can give the
// `snippets` package the ability to ask about all of a grammar's comment
// tokens — both line and block.
// Returns the correct comment delimiters for the given buffer position. This
// may be defined on the grammar itself, but it can also be defined as a
// scope-specific setting for scenarios where a language has different
// comment delimiters for different contexts.
//
// TODO: Our understanding of the correct delimiters for a given buffer
// position is only as granular as the entire buffer row. This can bite us in
// edge cases like JSX. It's the right decision if the user toggles a comment
// with an empty selection, but if specific buffer text is selected, we
// should look up the right delmiters for that specific range. This will
// require a new branch in the “Editor: Toggle Line Comments” command.
commentStringsForPosition(position) {
// First ask the grammar for its comment strings.
const range = this.firstNonWhitespaceRange(position.row) ||
new Range(position, position);
// Ask the config system if it has a setting for this scope. This allows
// for overrides from the grammar default.
const scope = this.scopeDescriptorForPosition(range.start);
const commentStartEntries = this.config.getAll(
'editor.commentStart', { scope });
const commentEndEntries = this.config.getAll(
'editor.commentEnd', { scope });
const commentStartEntry = commentStartEntries[0];
const commentEndEntry = commentEndEntries.find(entry => (
entry.scopeSelector === commentStartEntry.scopeSelector
));
if (commentStartEntry) {
return {
commentStartString: commentStartEntry && commentStartEntry.value,
commentEndString: commentEndEntry && commentEndEntry.value
};
}
// Fall back to looking up this information on the grammar.
const { grammar } = this.getSyntaxNodeAndGrammarContainingRange(range);
if (grammar) {
@ -1079,22 +1102,6 @@ class WASMTreeSitterLanguageMode {
return commentStrings;
}
}
// Fall back to a lookup through the config system.
const scope = this.scopeDescriptorForPosition(position);
const commentStartEntries = this.config.getAll(
'editor.commentStart', { scope });
const commentEndEntries = this.config.getAll(
'editor.commentEnd', { scope });
const commentStartEntry = commentStartEntries[0];
const commentEndEntry = commentEndEntries.find(entry => (
entry.scopeSelector === commentStartEntry.scopeSelector
));
return {
commentStartString: commentStartEntry && commentStartEntry.value,
commentEndString: commentEndEntry && commentEndEntry.value
};
}
isRowCommented(row) {
@ -1124,7 +1131,7 @@ class WASMTreeSitterLanguageMode {
break;
}
}
return indentLength / tabLength;
return Math.floor(indentLength / tabLength);
}
// Get the suggested indentation level for an existing line in the buffer.
@ -1642,6 +1649,11 @@ class WASMTreeSitterLanguageMode {
}
}
if (!indentTree) {
console.error(`No indent tree!`, controllingLayer.inspect());
return undefined;
}
const indents = indentsQuery.captures(
indentTree.rootNode,
{ row: row, column: 0 },
@ -2821,10 +2833,10 @@ class GrammarLoadError extends Error {
constructor(grammar, queryType) {
super(`Grammar ${grammar.scopeName} failed to load its ${queryType}. Please fix this error or contact the maintainer.`);
this.name = 'GrammarLoadError';
this.queryType = queryType;
}
}
// Manages all aspects of a given language's parsing duties over a given region
// of the buffer.
//
@ -2898,6 +2910,13 @@ class LanguageLayer {
}).catch((err) => {
if (err.name === 'GrammarLoadError') {
console.warn(err.message);
if (err.queryType === 'highlightsQuery') {
// TODO: Warning?
grammar.highlightsQuery = grammar.setQueryForTest(
'highlightsQuery',
`; (placeholder)`
);
}
} else {
throw err;
}
@ -2921,12 +2940,17 @@ class LanguageLayer {
if (depth === 0) {
languageScope = this.grammar.scopeName;
} else {
// Injections can control the base scope name of the grammar being
// injected.
languageScope = injectionPoint.languageScope;
// Honor an explicit `null`, but fall back to the default scope name
// otherwise.
// The `languageScope` parameter can be a function.
if (typeof languageScope === 'function') {
languageScope = languageScope(this.grammar);
}
// Honor an explicit `null`, but fall back to the default scope name
// otherwise.
if (languageScope === undefined) {
languageScope = this.grammar.scopeName;
}