diff --git a/packages/bracket-matcher/lib/bracket-matcher-view.js b/packages/bracket-matcher/lib/bracket-matcher-view.js index 4290d1968..76df8006e 100644 --- a/packages/bracket-matcher/lib/bracket-matcher-view.js +++ b/packages/bracket-matcher/lib/bracket-matcher-view.js @@ -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 } } diff --git a/packages/language-c/grammars/tree-sitter-c/highlights.scm b/packages/language-c/grammars/tree-sitter-c/highlights.scm index 402b1069d..a85ee5977 100644 --- a/packages/language-c/grammars/tree-sitter-c/highlights.scm +++ b/packages/language-c/grammars/tree-sitter-c/highlights.scm @@ -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 diff --git a/packages/language-c/grammars/tree-sitter-c/locals.scm b/packages/language-c/grammars/tree-sitter-c/locals.scm deleted file mode 100644 index 092bc2b04..000000000 --- a/packages/language-c/grammars/tree-sitter-c/locals.scm +++ /dev/null @@ -1 +0,0 @@ -; diff --git a/packages/language-c/grammars/tree-sitter-c/tags.scm b/packages/language-c/grammars/tree-sitter-c/tags.scm index 3ef41679a..491007448 100644 --- a/packages/language-c/grammars/tree-sitter-c/tags.scm +++ b/packages/language-c/grammars/tree-sitter-c/tags.scm @@ -1,2 +1,3 @@ -((function_declarator (identifier) @name)) +(function_declarator + (identifier) @name) @definition.function diff --git a/packages/language-c/grammars/tree-sitter-cpp/highlights.scm b/packages/language-c/grammars/tree-sitter-cpp/highlights.scm index 634aa8535..ed0d2ebc9 100644 --- a/packages/language-c/grammars/tree-sitter-cpp/highlights.scm +++ b/packages/language-c/grammars/tree-sitter-cpp/highlights.scm @@ -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" diff --git a/packages/language-c/grammars/tree-sitter-cpp/locals.scm b/packages/language-c/grammars/tree-sitter-cpp/locals.scm deleted file mode 100644 index 092bc2b04..000000000 --- a/packages/language-c/grammars/tree-sitter-cpp/locals.scm +++ /dev/null @@ -1 +0,0 @@ -; diff --git a/packages/language-c/grammars/tree-sitter-cpp/tags.scm b/packages/language-c/grammars/tree-sitter-cpp/tags.scm index 3ef41679a..c44ee78e4 100644 --- a/packages/language-c/grammars/tree-sitter-cpp/tags.scm +++ b/packages/language-c/grammars/tree-sitter-cpp/tags.scm @@ -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")) diff --git a/packages/language-css/grammars/tree-sitter/queries/highlights.scm b/packages/language-css/grammars/tree-sitter/queries/highlights.scm index 4301691ed..4c4cc597d 100644 --- a/packages/language-css/grammars/tree-sitter/queries/highlights.scm +++ b/packages/language-css/grammars/tree-sitter/queries/highlights.scm @@ -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? diff --git a/packages/language-javascript/grammars/ts/folds.scm b/packages/language-javascript/grammars/ts/folds.scm index d9b0e5142..d907958ad 100644 --- a/packages/language-javascript/grammars/ts/folds.scm +++ b/packages/language-javascript/grammars/ts/folds.scm @@ -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… diff --git a/packages/language-javascript/grammars/ts/highlights.scm b/packages/language-javascript/grammars/ts/highlights.scm index 8ce5bf717..74f81c9cc 100644 --- a/packages/language-javascript/grammars/ts/highlights.scm +++ b/packages/language-javascript/grammars/ts/highlights.scm @@ -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 ; ==== diff --git a/packages/language-javascript/grammars/ts/indents.scm b/packages/language-javascript/grammars/ts/indents.scm index ce46a1393..6aab803c1 100644 --- a/packages/language-javascript/grammars/ts/indents.scm +++ b/packages/language-javascript/grammars/ts/indents.scm @@ -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) diff --git a/packages/language-javascript/grammars/ts/jsdoc/highlights.scm b/packages/language-javascript/grammars/ts/jsdoc/highlights.scm index 549d7c384..b9231f22b 100644 --- a/packages/language-javascript/grammars/ts/jsdoc/highlights.scm +++ b/packages/language-javascript/grammars/ts/jsdoc/highlights.scm @@ -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 diff --git a/packages/language-javascript/grammars/ts/tags.scm b/packages/language-javascript/grammars/ts/tags.scm index b89f362be..5063d183f 100644 --- a/packages/language-javascript/grammars/ts/tags.scm +++ b/packages/language-javascript/grammars/ts/tags.scm @@ -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) diff --git a/packages/language-javascript/lib/main.js b/packages/language-javascript/lib/main.js index a6488be3a..9df866a6e 100644 --- a/packages/language-javascript/lib/main.js +++ b/packages/language-javascript/lib/main.js @@ -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 - }); - } - } }; diff --git a/packages/language-javascript/settings/language-javascript.cson b/packages/language-javascript/settings/language-javascript.cson index 37198cb09..48b832fb6 100644 --- a/packages/language-javascript/settings/language-javascript.cson +++ b/packages/language-javascript/settings/language-javascript.cson @@ -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': '*/}' diff --git a/packages/language-javascript/snippets/language-javascript.cson b/packages/language-javascript/snippets/language-javascript.cson index cef3df690..47ffd586b 100644 --- a/packages/language-javascript/snippets/language-javascript.cson +++ b/packages/language-javascript/snippets/language-javascript.cson @@ -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},' diff --git a/packages/language-json/grammars/tree-sitter/queries/tags.scm b/packages/language-json/grammars/tree-sitter/queries/tags.scm index 3c7d1defe..3e04140c3 100644 --- a/packages/language-json/grammars/tree-sitter/queries/tags.scm +++ b/packages/language-json/grammars/tree-sitter/queries/tags.scm @@ -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 "."))) diff --git a/packages/language-ruby/grammars/ts/regex/highlights.scm b/packages/language-ruby/grammars/ts/regex/highlights.scm index 85255d818..b0018b6c7 100644 --- a/packages/language-ruby/grammars/ts/regex/highlights.scm +++ b/packages/language-ruby/grammars/ts/regex/highlights.scm @@ -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 [ diff --git a/packages/language-ruby/lib/main.js b/packages/language-ruby/lib/main.js index df1a0041f..5f343a42f 100644 --- a/packages/language-ruby/lib/main.js +++ b/packages/language-ruby/lib/main.js @@ -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 }); diff --git a/packages/language-shellscript/lib/main.js b/packages/language-shellscript/lib/main.js new file mode 100644 index 000000000..e2eb7368a --- /dev/null +++ b/packages/language-shellscript/lib/main.js @@ -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 + }); + +}; diff --git a/packages/language-shellscript/package.json b/packages/language-shellscript/package.json index 68a12c900..47fa9bc27 100644 --- a/packages/language-shellscript/package.json +++ b/packages/language-shellscript/package.json @@ -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", diff --git a/packages/language-typescript/grammars/common/folds.scm b/packages/language-typescript/grammars/common/folds.scm index cbe82351f..97c5a6f0f 100644 --- a/packages/language-typescript/grammars/common/folds.scm +++ b/packages/language-typescript/grammars/common/folds.scm @@ -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)) diff --git a/packages/language-typescript/grammars/common/highlights.scm b/packages/language-typescript/grammars/common/highlights.scm index e83dac3d1..385ccfff2 100644 --- a/packages/language-typescript/grammars/common/highlights.scm +++ b/packages/language-typescript/grammars/common/highlights.scm @@ -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` diff --git a/packages/language-typescript/grammars/common/indents.scm b/packages/language-typescript/grammars/common/indents.scm index a85c78b0a..427f19f0c 100644 --- a/packages/language-typescript/grammars/common/indents.scm +++ b/packages/language-typescript/grammars/common/indents.scm @@ -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 diff --git a/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm b/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm index e0f995633..c8b90d23a 100644 --- a/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm +++ b/packages/language-typescript/grammars/tree-sitter-tsx/highlights.scm @@ -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)) diff --git a/packages/language-typescript/grammars/tree-sitter-tsx/indents.scm b/packages/language-typescript/grammars/tree-sitter-tsx/indents.scm index dee9c2f64..bd25180c1 100644 --- a/packages/language-typescript/grammars/tree-sitter-tsx/indents.scm +++ b/packages/language-typescript/grammars/tree-sitter-tsx/indents.scm @@ -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) diff --git a/packages/language-typescript/lib/main.js b/packages/language-typescript/lib/main.js index e226ed8ce..dd7f40051 100644 --- a/packages/language-typescript/lib/main.js +++ b/packages/language-typescript/lib/main.js @@ -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) { diff --git a/packages/language-typescript/settings/TypeScriptReact.cson b/packages/language-typescript/settings/TypeScriptReact.cson index 941998002..4ffd62638 100644 --- a/packages/language-typescript/settings/TypeScriptReact.cson +++ b/packages/language-typescript/settings/TypeScriptReact.cson @@ -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*()" \ No newline at end of file + 'decreaseIndentPattern': "^\\s*(\\s*/[*].*[*]/\\s*)*[}\\])]|^\\s*()" diff --git a/packages/language-yaml/grammars/tree-sitter/highlights.scm b/packages/language-yaml/grammars/tree-sitter/highlights.scm index 14e10bfcc..2f45509bb 100644 --- a/packages/language-yaml/grammars/tree-sitter/highlights.scm +++ b/packages/language-yaml/grammars/tree-sitter/highlights.scm @@ -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 diff --git a/packages/language-yaml/grammars/tree-sitter/indents.scm b/packages/language-yaml/grammars/tree-sitter/indents.scm index 05dec1522..1cf9c2ad2 100644 --- a/packages/language-yaml/grammars/tree-sitter/indents.scm +++ b/packages/language-yaml/grammars/tree-sitter/indents.scm @@ -1,4 +1,4 @@ (":" @indent - (#set! test.onlyIfLastTextOnRow true)) + (#is? test.lastTextOnRow true)) ["|" ">"] @indent diff --git a/packages/language-yaml/grammars/tree-sitter/tags.scm b/packages/language-yaml/grammars/tree-sitter/tags.scm index c5983fe84..4d76571af 100644 --- a/packages/language-yaml/grammars/tree-sitter/tags.scm +++ b/packages/language-yaml/grammars/tree-sitter/tags.scm @@ -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 ".")) diff --git a/spec/scope-resolver-spec.js b/spec/scope-resolver-spec.js index 5f7611d87..ccd2af6b2 100644 --- a/spec/scope-resolver-spec.js +++ b/spec/scope-resolver-spec.js @@ -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; diff --git a/src/scope-resolver.js b/src/scope-resolver.js index 5ce0a33dd..559389bf4 100644 --- a/src/scope-resolver.js +++ b/src/scope-resolver.js @@ -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 diff --git a/src/wasm-tree-sitter-grammar.js b/src/wasm-tree-sitter-grammar.js index 3ebb0aa4b..c14588fff 100644 --- a/src/wasm-tree-sitter-grammar.js +++ b/src/wasm-tree-sitter-grammar.js @@ -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 diff --git a/src/wasm-tree-sitter-language-mode.js b/src/wasm-tree-sitter-language-mode.js index bfba2af77..559274b4d 100644 --- a/src/wasm-tree-sitter-language-mode.js +++ b/src/wasm-tree-sitter-language-mode.js @@ -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; }