Unnamed repository; edit this file 'description' to name the repository.
Use tree-sitter-htmlx for Svelte grammar (#15468)
* Use tree-sitter-htmlx for Svelte grammar
* Update Svelte queries for htmlx grammar
* Fix Svelte runtime queries
* Fix Svelte style injections
| -rw-r--r-- | book/src/generated/lang-support.md | 2 | ||||
| -rw-r--r-- | languages.toml | 2 | ||||
| -rw-r--r-- | runtime/queries/svelte/folds.scm | 20 | ||||
| -rw-r--r-- | runtime/queries/svelte/highlights.scm | 147 | ||||
| -rw-r--r-- | runtime/queries/svelte/indents.scm | 28 | ||||
| -rw-r--r-- | runtime/queries/svelte/injections.scm | 186 | ||||
| -rw-r--r-- | runtime/queries/svelte/locals.scm | 9 | ||||
| -rw-r--r-- | runtime/queries/svelte/rainbows.scm | 47 | ||||
| -rw-r--r-- | runtime/queries/svelte/tags.scm | 11 | ||||
| -rw-r--r-- | runtime/queries/svelte/textobjects.scm | 11 |
10 files changed, 366 insertions, 97 deletions
diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index a3294acd..3accd33f 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -277,7 +277,7 @@ | strictdoc | ✓ | | | ✓ | | | | styx | ✓ | ✓ | ✓ | | ✓ | `styx` | | supercollider | ✓ | | | | | | -| svelte | ✓ | ✓ | ✓ | | ✓ | `svelteserver` | +| svelte | ✓ | ✓ | ✓ | ✓ | ✓ | `svelteserver` | | sway | ✓ | ✓ | ✓ | | | `forc` | | swift | ✓ | ✓ | ✓ | | ✓ | `sourcekit-lsp` | | systemd | ✓ | | | ✓ | | `systemd-lsp` | diff --git a/languages.toml b/languages.toml index 9de6c04e..edbf7f6b 100644 --- a/languages.toml +++ b/languages.toml @@ -1649,7 +1649,7 @@ language-servers = [ "svelteserver" ] [[grammar]] name = "svelte" -source = { git = "https://github.com/tree-sitter-grammars/tree-sitter-svelte", rev = "ae5199db47757f785e43a14b332118a5474de1a2" } +source = { git = "https://github.com/themixednuts/tree-sitter-htmlx", rev = "3be6db3dc94478b089a64e59e4d855fc3041a7be", subpath = "crates/tree-sitter-svelte" } [[language]] name = "vue" diff --git a/runtime/queries/svelte/folds.scm b/runtime/queries/svelte/folds.scm index 6440301a..e50b368b 100644 --- a/runtime/queries/svelte/folds.scm +++ b/runtime/queries/svelte/folds.scm @@ -1,13 +1,11 @@ -; inherits: html - [ - (if_statement) - (else_if_block) - (else_block) - (each_statement) - (await_statement) - (then_block) - (catch_block) - (key_statement) - (snippet_statement) + (element) + (if_block) + (else_if_clause) + (else_clause) + (each_block) + (await_block) + (await_branch) + (key_block) + (snippet_block) ] @fold diff --git a/runtime/queries/svelte/highlights.scm b/runtime/queries/svelte/highlights.scm index 12e1bcd0..141cbb89 100644 --- a/runtime/queries/svelte/highlights.scm +++ b/runtime/queries/svelte/highlights.scm @@ -1,40 +1,139 @@ -; inherits: html +; Tag names +(tag_name) @tag +; Erroneous/mismatched end tags +(erroneous_end_tag_name) @error + +; DOCTYPE declaration +(doctype) @constant + +; Attribute names +(attribute_name) @attribute + +; Attribute values +(attribute_value) @string +(quoted_attribute_value) @string + +; Comments +(comment) @comment + +; Character entities +(entity) @string.special.symbol + +; Text content +(text) @text + +; Raw text in script/style (raw_text) @none +; HTML punctuation [ - "as" - "key" - "html" - "debug" - "snippet" - "render" -] @keyword + "<" + ">" + "</" + "/>" + "<!" +] @punctuation.bracket -"const" @keyword.storage.modifier +"=" @punctuation.delimiter -[ - "if" - "else if" - "else" - "then" - "await" -] @keyword.control.conditional +; Component tags (PascalCase) +((tag_name) @type (#match? @type "^[A-Z]")) + +; Namespaced tags (svelte:component, svelte:self, etc.) +(tag_name + namespace: (tag_namespace) @keyword + ":" @punctuation.delimiter + name: (tag_local_name) @tag) + +; Tag member access (Foo.Bar) +(tag_name + object: (tag_member) @type + "." @punctuation.delimiter + property: (tag_member) @tag) -"each" @keyword.control.repeat +; Directives (on:click, bind:value, etc.) +(attribute_directive) @keyword +(attribute_name ":" @punctuation.delimiter) +(attribute_identifier) @property +(attribute_modifier) @attribute +(attribute_modifiers "|" @punctuation.delimiter) -"catch" @keyword.control.exception +; Expressions +(expression) @embedded +(expression_value) @embedded +; Shorthand/spread attributes +(shorthand_attribute content: (_) @variable) + +; Curly braces (expression context) [ "{" "}" ] @punctuation.bracket +"|" @punctuation.delimiter + +; Comments inside tag attribute lists +(tag_comment kind: (line_comment) @comment) +(tag_comment kind: (block_comment) @comment) + +; Block keywords [ - "#" - ":" - "/" - "@" -] @punctuation.delimiter + "if" + "each" + "await" + "key" + "snippet" + "else" + "html" + "debug" + "const" + "render" + "attach" + "as" +] @keyword.control -(snippet_name) @function +; Block end keywords ({/if}, {/each}, etc.) +(block_keyword) @keyword.control + +; Block delimiters +(block_open) @punctuation.bracket +(block_close) @punctuation.bracket + +(shorthand_kind) @keyword.control +(branch_kind) @keyword.control + +; If block +(if_block expression: (expression) @embedded) +(else_if_clause expression: (expression_value) @embedded) + +; Each block +(each_block expression: (expression) @embedded) +(each_block binding: (pattern) @variable) +(each_block index: (pattern) @variable) +(each_block key: (expression) @embedded) + +; Await block +(await_block expression: (expression) @embedded) +(await_branch (pattern) @variable) +(await_block (pattern) @variable) +(orphan_branch (pattern) @variable) + +; Key block +(key_block expression: (expression) @embedded) + +; Snippet block +(snippet_block name: (snippet_name) @function) +(snippet_parameters parameter: (pattern) @variable) +(snippet_type_parameters) @type + +; Malformed blocks +(block_sigil) @keyword.control + +; Snippet/render punctuation +[ + "(" + ")" + "," +] @punctuation.delimiter diff --git a/runtime/queries/svelte/indents.scm b/runtime/queries/svelte/indents.scm index 4bb103d7..4e4e0904 100644 --- a/runtime/queries/svelte/indents.scm +++ b/runtime/queries/svelte/indents.scm @@ -1,24 +1,20 @@ [ (element) - (start_tag) - (if_statement) - (else_if_block) - (else_block) - (then_block) - (each_statement) - (key_statement) - (snippet_statement) - (await_statement) - (style_element) - (script_element) + (if_block) + (else_if_clause) + (else_clause) + (await_branch) + (each_block) + (key_block) + (snippet_block) + (await_block) (expression) ] @indent [ (end_tag) - (if_end) - (each_end) - (await_end) - (key_end) - (snippet_end) + (block_end) + (else_if_clause) + (else_clause) + (await_branch) ] @outdent diff --git a/runtime/queries/svelte/injections.scm b/runtime/queries/svelte/injections.scm index c94373c1..d40ae322 100644 --- a/runtime/queries/svelte/injections.scm +++ b/runtime/queries/svelte/injections.scm @@ -1,46 +1,182 @@ -; inherits html -((style_element +; Script elements with TypeScript aliases +((element (start_tag + (tag_name) @_tag (attribute - (attribute_name) @_attr (quoted_attribute_value - (attribute_value) @_lang))) + (attribute_value) @_value))) (raw_text) @injection.content) - (#eq? @_attr "lang") - (#any-of? @_lang "scss" "postcss" "less") - (#set! injection.language "scss")) - -((svelte_raw_text) @injection.content + (#match? @_tag "^[Ss][Cc][Rr][Ii][Pp][Tt]$") + (#any-of? @_value "ts" "typescript" "text/typescript") (#set! injection.language "typescript")) -((script_element +; Script elements with explicit language +((element (start_tag + (tag_name) @_tag (attribute - (attribute_name) @_attr + (attribute_name) @_lang (quoted_attribute_value - (attribute_value) @_lang))) + (attribute_value) @injection.language))) (raw_text) @injection.content) - (#eq? @_attr "lang") - (#any-of? @_lang "ts" "typescript") - (#set! injection.language "typescript")) + (#eq? @_tag "script") + (#eq? @_lang "lang") + (#not-any-of? @injection.language "ts" "typescript" "text/typescript")) + +; Script content defaults to JavaScript +((element + (start_tag (tag_name) @_tag) + (raw_text) @injection.content) + (#eq? @_tag "script") + (#set! injection.language "javascript")) -((script_element +; Style with lang="scss" +((element (start_tag + (tag_name) @_tag (attribute - (attribute_name) @_attr (quoted_attribute_value - (attribute_value) @_lang))) + (attribute_value) @_scss))) (raw_text) @injection.content) - (#eq? @_attr "lang") - (#any-of? @_lang "js" "javascript") - (#set! injection.language "javascript")) + (#eq? @_tag "style") + (#eq? @_scss "scss") + (#set! injection.language "scss")) + +; Style with lang="sass" +((element + (start_tag + (tag_name) @_tag + (attribute + (quoted_attribute_value + (attribute_value) @_sass))) + (raw_text) @injection.content) + (#eq? @_tag "style") + (#eq? @_sass "sass") + (#set! injection.language "sass")) +; Style with lang="less" ((element (start_tag + (tag_name) @_tag (attribute - (attribute_name) @_attr + (quoted_attribute_value + (attribute_value) @_less))) + (raw_text) @injection.content) + (#eq? @_tag "style") + (#eq? @_less "less") + (#set! injection.language "less")) + +; Style with explicit language +((element + (start_tag + (tag_name) @_tag + (attribute + (attribute_name) @_lang (quoted_attribute_value (attribute_value) @injection.language))) - (text) @injection.content) - (#eq? @_attr "lang") - (#eq? @injection.language "pug")) + (raw_text) @injection.content) + (#eq? @_tag "style") + (#eq? @_lang "lang") + (#not-any-of? @injection.language "scss" "sass" "less")) + +; Style content defaults to CSS when no lang attribute is present +((element + (start_tag + (tag_name) @_tag + (attribute + (attribute_name) @_style_attr)*) + (raw_text) @injection.content) + (#eq? @_tag "style") + (#not-any-of? @_style_attr "lang") + (#set! injection.language "css")) + +; Inline style attribute +((attribute + (attribute_name) @_style_name + (quoted_attribute_value (attribute_value) @injection.content)) + (#eq? @_style_name "style") + (#set! injection.language "css")) + +; Typed expression content +((expression content: (js) @injection.content) + (#set! injection.language "javascript")) +((expression content: (ts) @injection.content) + (#set! injection.language "typescript")) + +; Shorthand attributes ({foo}) +((shorthand_attribute content: (js) @injection.content) + (#set! injection.language "javascript")) +((shorthand_attribute content: (ts) @injection.content) + (#set! injection.language "typescript")) + +; Tag expressions ({@const}, {@render}, {@html}, {@debug}, {@attach}, {:else if}) +((expression_value content: (js) @injection.content) + (#set! injection.language "javascript")) +((expression_value content: (ts) @injection.content) + (#set! injection.language "typescript")) + +; Else-if clause +((else_if_clause expression: (expression_value content: (js) @injection.content)) + (#set! injection.language "javascript")) +((else_if_clause expression: (expression_value content: (ts) @injection.content)) + (#set! injection.language "typescript")) + +; If block expressions +((if_block expression: (expression content: (js) @injection.content)) + (#set! injection.language "javascript")) +((if_block expression: (expression content: (ts) @injection.content)) + (#set! injection.language "typescript")) + +; Each block expressions and bindings +((each_block expression: (expression content: (js) @injection.content)) + (#set! injection.language "javascript")) +((each_block expression: (expression content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((each_block binding: (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((each_block binding: (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((each_block index: (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((each_block index: (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((each_block key: (expression content: (js) @injection.content)) + (#set! injection.language "javascript")) +((each_block key: (expression content: (ts) @injection.content)) + (#set! injection.language "typescript")) + +; Await block expressions and bindings +((await_block expression: (expression content: (js) @injection.content)) + (#set! injection.language "javascript")) +((await_block expression: (expression content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((await_block (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((await_block (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((await_branch (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((await_branch (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((orphan_branch (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((orphan_branch (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) + +; Key block expressions +((key_block expression: (expression content: (js) @injection.content)) + (#set! injection.language "javascript")) +((key_block expression: (expression content: (ts) @injection.content)) + (#set! injection.language "typescript")) + +; Snippet parameters and type parameters +((snippet_parameters parameter: (pattern content: (js) @injection.content)) + (#set! injection.language "javascript")) +((snippet_parameters parameter: (pattern content: (ts) @injection.content)) + (#set! injection.language "typescript")) +((snippet_block type_parameters: (snippet_type_parameters) @injection.content) + (#set! injection.language "typescript")) + +; Comments +((comment) @injection.content + (#set! injection.language "comment")) diff --git a/runtime/queries/svelte/locals.scm b/runtime/queries/svelte/locals.scm index 1f2129cf..14f11b09 100644 --- a/runtime/queries/svelte/locals.scm +++ b/runtime/queries/svelte/locals.scm @@ -1 +1,8 @@ -; inherits: html +(snippet_block) @local.scope + +(snippet_parameters + parameter: (pattern) @local.definition.variable.parameter) + +(snippet_name) @local.definition.function + +(tag_name) @local.reference diff --git a/runtime/queries/svelte/rainbows.scm b/runtime/queries/svelte/rainbows.scm index d05058e2..ce95ffd3 100644 --- a/runtime/queries/svelte/rainbows.scm +++ b/runtime/queries/svelte/rainbows.scm @@ -1,25 +1,38 @@ -; inherits: html +[ + (doctype) + (erroneous_end_tag) +] @rainbow.scope + +([ + (element) + ] @rainbow.scope + (#set! rainbow.include-children)) [ - (if_start) - (else_if_start) - (else_start) - (if_end) - (each_start) - (each_end) - (await_start) - (then_start) - (catch_start) - (await_end) - (key_start) - (key_end) - (snippet_start) - (snippet_end) - (expression) + (if_block) + (else_if_clause) + (else_clause) + (each_block) + (await_block) + (await_branch) + (attach_tag) (html_tag) (const_tag) (debug_tag) (render_tag) + (key_block) + (snippet_block) + (expression) ] @rainbow.scope -["{" "}"] @rainbow.bracket +[ + "<" + ">" + "<!" + "</" + "/>" + (block_open) + (block_close) + "{" + "}" +] @rainbow.bracket diff --git a/runtime/queries/svelte/tags.scm b/runtime/queries/svelte/tags.scm new file mode 100644 index 00000000..c2fcb1c2 --- /dev/null +++ b/runtime/queries/svelte/tags.scm @@ -0,0 +1,11 @@ +; Snippet declarations +(snippet_block + name: (snippet_name) @name) @definition.function + +; Component references +((tag_name) @name @reference.class + (#match? @name "^[A-Z]")) + +(tag_name + object: (tag_member) @name + property: (tag_member) @name) @reference.class diff --git a/runtime/queries/svelte/textobjects.scm b/runtime/queries/svelte/textobjects.scm index 1f2129cf..12fa8b77 100644 --- a/runtime/queries/svelte/textobjects.scm +++ b/runtime/queries/svelte/textobjects.scm @@ -1 +1,10 @@ -; inherits: html +(element (start_tag) (_)* @xml-element.inside (end_tag)) + +(element) @xml-element.around + +(comment) @comment.around + +(snippet_block + parameters: (snippet_parameters) @parameter.inside) @function.around + +(snippet_name) @function.inside |