svelte: Migrate to tree-sitter-grammars/tree-sitter-svelte
(#17529)
> [!NOTE] > The https://github.com/tree-sitter-grammars/tree-sitter-svelte repository seems to be more well maintained, with higher quality code, and as per https://github.com/zed-extensions/svelte/issues/1 it was suggested that we swap to this repository for Svelte grammars - Closes https://github.com/zed-industries/zed/issues/17310 - Closes https://github.com/zed-industries/zed/issues/10893 - Closes https://github.com/zed-industries/zed/issues/12833 - Closes https://github.com/zed-extensions/svelte/issues/1 - Closes https://github.com/zed-industries/zed/issues/14943 - Closes https://github.com/zed-extensions/svelte/issues/2 - Added: buffer/file symbol outlines for `.svelte` (`outlines.scm`) - Improved: Attribute directives & modifiers in `.svelte` files can be styled independently. - Fixed: issue where svelte expression inside quotes failed parsing - Improved: Svelte components in Markup are styled differently from tags. - Added: Support for Svelte 5 syntax (`{#snippet children()}`, `{@render foo()`) - Change: Svelte now using [tree-sitter-grammars/tree-sitter-svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte) for language highlighting - Added: Support for typescript syntax in svelte expressions   Release Notes: - N/A --- **tree-sitter-grammar things to improve** - [ ] snippet functions aren't being treated as JS code - [ ] we should be able to detect @component comments and treat them as markdown - [x] `foo:bar` style/class/prop directives - [x] `--foo="..."` var fields - [ ] snippet/if blocks's children may need to be indented a little further Will implement some of the rest of these in a separate PR --------- Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
This commit is contained in:
parent
27f09957c2
commit
accff826ca
7 changed files with 271 additions and 113 deletions
|
@ -2,16 +2,29 @@
|
||||||
|
|
||||||
Svelte support is available through the [Svelte extension](https://github.com/zed-industries/zed/tree/main/extensions/svelte).
|
Svelte support is available through the [Svelte extension](https://github.com/zed-industries/zed/tree/main/extensions/svelte).
|
||||||
|
|
||||||
- Tree Sitter: [Himujjal/tree-sitter-svelte](https://github.com/Himujjal/tree-sitter-svelte)
|
- Tree Sitter: [tree-sitter-grammars/tree-sitter-svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte)
|
||||||
- Language Server: [sveltejs/language-tools](https://github.com/sveltejs/language-tools)
|
- Language Server: [sveltejs/language-tools](https://github.com/sveltejs/language-tools)
|
||||||
|
|
||||||
<!--
|
## Extra theme styling configuration
|
||||||
TBD: Rewrite Svelte docs so it doesn't begin with a json block assuming you know what inlayHints are.
|
|
||||||
-->
|
You can modify how certain styles such as directives and modifiers appear in attributes:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"syntax": {
|
||||||
|
// Styling for directives (e.g., `class:foo` or `on:click`) (the `on` or `class` part of the attribute).
|
||||||
|
"attribute.function": {
|
||||||
|
"color": "#ff0000"
|
||||||
|
},
|
||||||
|
// Styling for modifiers at the end of attributes, e.g. `on:<click|preventDefault|stopPropagation>`
|
||||||
|
"attribute.special": {
|
||||||
|
"color": "#00ff00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Inlay Hints
|
## Inlay Hints
|
||||||
|
|
||||||
Zed sets the following initialization options for inlay Hints:
|
Zed sets the following initialization options for inlay hints:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"inlayHints": {
|
"inlayHints": {
|
||||||
|
|
|
@ -11,5 +11,5 @@ name = "Svelte Language Server"
|
||||||
language = "Svelte"
|
language = "Svelte"
|
||||||
|
|
||||||
[grammars.svelte]
|
[grammars.svelte]
|
||||||
repository = "https://github.com/Himujjal/tree-sitter-svelte"
|
repository = "https://github.com/tree-sitter-grammars/tree-sitter-svelte"
|
||||||
commit = "b08d070e303d2a385d6d0ab3add500f8fa514443"
|
commit = "3f06f705410683adb17d146b5eca28c62fe81ba6"
|
||||||
|
|
7
extensions/svelte/languages/svelte/brackets.scm
Normal file
7
extensions/svelte/languages/svelte/brackets.scm
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
("<" @open ">" @close)
|
||||||
|
("{" @open "}" @close)
|
||||||
|
("'" @open "'" @close)
|
||||||
|
("\"" @open "\"" @close)
|
||||||
|
("(" @open ")" @close)
|
||||||
|
; ("[" @open "]" @close)
|
||||||
|
; ("`" @open "`" @close)
|
|
@ -2,16 +2,16 @@ name = "Svelte"
|
||||||
grammar = "svelte"
|
grammar = "svelte"
|
||||||
path_suffixes = ["svelte"]
|
path_suffixes = ["svelte"]
|
||||||
block_comment = ["<!-- ", " -->"]
|
block_comment = ["<!-- ", " -->"]
|
||||||
autoclose_before = ";:.,=}])>"
|
autoclose_before = ":\"'}]>"
|
||||||
brackets = [
|
brackets = [
|
||||||
{ start = "{", end = "}", close = true, newline = true },
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
{ start = "<", end = ">", close = true, newline = true, not_in = ["string"] },
|
||||||
{ start = "[", end = "]", close = true, newline = true },
|
{ start = "[", end = "]", close = true, newline = true },
|
||||||
{ start = "(", end = ")", close = true, newline = true },
|
{ start = "(", end = ")", close = true, newline = true },
|
||||||
{ start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
|
{ start = "!--", end = " --", close = true, newline = true },
|
||||||
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
|
{ start = "\"", end = "\"", close = true, newline = true, not_in = ["string"] },
|
||||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
|
{ start = "'", end = "'", close = true, newline = true, not_in = ["string"] },
|
||||||
{ start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
|
{ start = "`", end = "`", close = true, newline = true, not_in = ["string"] },
|
||||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
|
||||||
]
|
]
|
||||||
scope_opt_in_language_servers = ["tailwindcss-language-server"]
|
scope_opt_in_language_servers = ["tailwindcss-language-server"]
|
||||||
prettier_parser_name = "svelte"
|
prettier_parser_name = "svelte"
|
||||||
|
|
|
@ -1,50 +1,107 @@
|
||||||
; Special identifiers
|
|
||||||
;--------------------
|
|
||||||
|
|
||||||
; Treat capitalized tag names as constructors and types
|
; comments
|
||||||
((tag_name) @type
|
|
||||||
(#match? @type "^[A-Z]"))
|
|
||||||
|
|
||||||
; Regular (lowercase) tag names
|
|
||||||
((tag_name) @tag
|
|
||||||
(#match? @tag "^[a-z]"))
|
|
||||||
|
|
||||||
; TODO:
|
|
||||||
(attribute_name) @property
|
|
||||||
(erroneous_end_tag_name) @keyword
|
|
||||||
(comment) @comment
|
(comment) @comment
|
||||||
|
|
||||||
[
|
; property attribute
|
||||||
(attribute_value)
|
(attribute_directive) @attribute.function
|
||||||
(quoted_attribute_value)
|
(attribute_identifier) @attribute
|
||||||
] @string
|
(attribute_modifier) @attribute.special
|
||||||
|
|
||||||
[
|
; Style component attributes as @property
|
||||||
(text)
|
(start_tag
|
||||||
(raw_text_expr)
|
(
|
||||||
(raw_text_each)
|
(tag_name) @_tag_name
|
||||||
] @none
|
(#match? @_tag_name "^[A-Z]")
|
||||||
|
)
|
||||||
|
(attribute
|
||||||
|
(attribute_name
|
||||||
|
(attribute_identifier) @tag.property
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
[
|
(self_closing_tag
|
||||||
(special_block_keyword)
|
(
|
||||||
(then)
|
(tag_name) @_tag_name
|
||||||
(as)
|
(#match? @_tag_name "^[A-Z]")
|
||||||
] @keyword
|
)
|
||||||
|
(attribute
|
||||||
|
(attribute_name
|
||||||
|
(attribute_identifier) @tag.property
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
[
|
|
||||||
"{"
|
|
||||||
"}"
|
|
||||||
] @punctuation.bracket
|
|
||||||
|
|
||||||
"=" @operator
|
; style elements starting with lowercase letters as tags
|
||||||
|
(
|
||||||
|
(tag_name) @tag
|
||||||
|
(#match? @tag "^[a-z]")
|
||||||
|
)
|
||||||
|
|
||||||
|
; style elements starting with uppercase letters as components (types)
|
||||||
|
; Also valid might be to treat them as constructors
|
||||||
|
(
|
||||||
|
(tag_name) @tag @tag.component.type.constructor
|
||||||
|
(#match? @tag "^[A-Z]")
|
||||||
|
)
|
||||||
|
|
||||||
[
|
[
|
||||||
"<"
|
"<"
|
||||||
">"
|
">"
|
||||||
"</"
|
"</"
|
||||||
"/>"
|
"/>"
|
||||||
|
] @tag.punctuation.bracket
|
||||||
|
|
||||||
|
|
||||||
|
[
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
|
||||||
|
[
|
||||||
|
"|"
|
||||||
|
] @punctuation.delimiter
|
||||||
|
|
||||||
|
|
||||||
|
[
|
||||||
|
"@"
|
||||||
"#"
|
"#"
|
||||||
":"
|
":"
|
||||||
"/"
|
"/"
|
||||||
"@"
|
] @tag.punctuation.special
|
||||||
] @tag.delimiter
|
|
||||||
|
"=" @operator
|
||||||
|
|
||||||
|
|
||||||
|
; Treating (if, each, ...) as a keyword inside of blocks
|
||||||
|
; like {#if ...} or {#each ...}
|
||||||
|
(block_start_tag
|
||||||
|
tag: _ @tag.keyword
|
||||||
|
)
|
||||||
|
|
||||||
|
(block_tag
|
||||||
|
tag: _ @tag.keyword
|
||||||
|
)
|
||||||
|
|
||||||
|
(block_end_tag
|
||||||
|
tag: _ @tag.keyword
|
||||||
|
)
|
||||||
|
|
||||||
|
(expression_tag
|
||||||
|
tag: _ @tag.keyword
|
||||||
|
)
|
||||||
|
|
||||||
|
; Style quoted string attribute values
|
||||||
|
(quoted_attribute_value) @string
|
||||||
|
|
||||||
|
|
||||||
|
; Highlight the `as` keyword in each blocks
|
||||||
|
(each_start
|
||||||
|
("as") @tag.keyword
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
; Highlight the snippet name as a function
|
||||||
|
; (e.g. {#snippet foo(bar)}
|
||||||
|
(snippet_name) @function
|
||||||
|
|
|
@ -1,74 +1,86 @@
|
||||||
; injections.scm
|
; ; injections.scm
|
||||||
; --------------
|
; ; --------------
|
||||||
|
|
||||||
; match script tags without a lang tag
|
; Match script tags with a lang attribute
|
||||||
((script_element
|
(script_element
|
||||||
(start_tag
|
(start_tag
|
||||||
(attribute
|
(attribute
|
||||||
(attribute_name) @_name)*)
|
(attribute_name) @_attr_name
|
||||||
(raw_text) @content)
|
(#eq? @_attr_name "lang")
|
||||||
(#not-eq? @_name "lang")
|
(quoted_attribute_value
|
||||||
(#set! "language" "javascript"))
|
(attribute_value) @language
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(raw_text) @content
|
||||||
|
)
|
||||||
|
|
||||||
; match javascript
|
; Match script tags without a lang attribute
|
||||||
((script_element
|
(script_element
|
||||||
(start_tag
|
(start_tag
|
||||||
(attribute
|
(attribute
|
||||||
(attribute_name) @_name
|
(attribute_name) @_attr_name
|
||||||
(quoted_attribute_value (attribute_value) @_value)))
|
)*
|
||||||
(raw_text) @content)
|
)
|
||||||
(#eq? @_name "lang")
|
(raw_text) @content
|
||||||
(#eq? @_value "js")
|
(#not-any-of? @_attr_name "lang")
|
||||||
(#set! "language" "javascript"))
|
(#set! language "javascript")
|
||||||
|
)
|
||||||
|
|
||||||
; match typescript
|
; Match the contents of the script's generics="T extends string" as typescript code
|
||||||
((script_element
|
;
|
||||||
(start_tag
|
; Disabled for the time-being because tree-sitter is treating the generics
|
||||||
(attribute
|
; attribute as a top-level typescript statement, where `T extends string` is
|
||||||
(attribute_name) @_name
|
; not a valid top-level typescript statement.
|
||||||
(quoted_attribute_value (attribute_value) @_value)))
|
;
|
||||||
(raw_text) @content)
|
; (script_element
|
||||||
(#eq? @_name "lang")
|
; (start_tag
|
||||||
(#eq? @_value "ts")
|
; (attribute
|
||||||
(#set! "language" "typescript"))
|
; (attribute_name) @_attr_name
|
||||||
|
; (#eq? @_attr_name "generics")
|
||||||
|
; (quoted_attribute_value
|
||||||
|
; (attribute_value) @content
|
||||||
|
; )
|
||||||
|
; )
|
||||||
|
; )
|
||||||
|
; (#set! language "typescript")
|
||||||
|
; )
|
||||||
|
|
||||||
|
|
||||||
|
; Mark everything as typescript because it's
|
||||||
|
; a more generic superset of javascript
|
||||||
|
; Not sure if it's possible to somehow refer to the
|
||||||
|
; script's language attribute here.
|
||||||
|
((svelte_raw_text) @content
|
||||||
|
(#set! "language" "ts")
|
||||||
|
)
|
||||||
|
|
||||||
|
; Match style tags with a lang attribute
|
||||||
(style_element
|
(style_element
|
||||||
(raw_text) @content
|
(start_tag
|
||||||
(#set! "language" "css"))
|
(attribute
|
||||||
|
(attribute_name) @_attr_name
|
||||||
|
(#eq? @_attr_name "lang")
|
||||||
|
(quoted_attribute_value
|
||||||
|
(attribute_value) @language
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(raw_text) @content
|
||||||
|
)
|
||||||
|
|
||||||
; match style tags without a lang tag
|
; Match style tags without a lang attribute
|
||||||
((style_element
|
(style_element
|
||||||
(start_tag
|
(start_tag
|
||||||
(attribute
|
(attribute
|
||||||
(attribute_name) @_name)*)
|
(attribute_name) @_attr_name
|
||||||
(raw_text) @content)
|
)*
|
||||||
(#not-eq? @_name "lang")
|
)
|
||||||
(#set! "language" "css"))
|
(raw_text) @content
|
||||||
|
(#not-any-of? @_attr_name "lang")
|
||||||
|
(#set! language "css")
|
||||||
|
)
|
||||||
|
|
||||||
; match css
|
|
||||||
((style_element
|
|
||||||
(start_tag
|
|
||||||
(attribute
|
|
||||||
(attribute_name) @_name
|
|
||||||
(quoted_attribute_value (attribute_value) @_value)))
|
|
||||||
(raw_text) @content)
|
|
||||||
(#eq? @_name "lang")
|
|
||||||
(#eq? @_value "css")
|
|
||||||
(#set! "language" "css"))
|
|
||||||
|
|
||||||
; match scss
|
; Downstream TODO: Style highlighting for `style:background="red"` and `style="background: red"` strings
|
||||||
((style_element
|
; Downstream TODO: Style component comments as markdown
|
||||||
(start_tag
|
|
||||||
(attribute
|
|
||||||
(attribute_name) @_name
|
|
||||||
(quoted_attribute_value (attribute_value) @_value)))
|
|
||||||
(raw_text) @content)
|
|
||||||
(#eq? @_name "lang")
|
|
||||||
(#eq? @_value "scss")
|
|
||||||
(#set! "language" "scss"))
|
|
||||||
|
|
||||||
((raw_text_expr) @content
|
|
||||||
(#set! "language" "javascript"))
|
|
||||||
|
|
||||||
((raw_text_each) @content
|
|
||||||
(#set! "language" "javascript"))
|
|
||||||
|
|
69
extensions/svelte/languages/svelte/outline.scm
Normal file
69
extensions/svelte/languages/svelte/outline.scm
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
|
||||||
|
(script_element
|
||||||
|
(start_tag) @name
|
||||||
|
(raw_text) @context @item
|
||||||
|
)
|
||||||
|
|
||||||
|
(script_element
|
||||||
|
(end_tag) @name @item
|
||||||
|
)
|
||||||
|
|
||||||
|
(style_element
|
||||||
|
(start_tag) @name
|
||||||
|
(raw_text) @context
|
||||||
|
) @item
|
||||||
|
|
||||||
|
|
||||||
|
(document) @item
|
||||||
|
|
||||||
|
(comment) @annotation
|
||||||
|
|
||||||
|
(if_statement
|
||||||
|
(if_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(else_block
|
||||||
|
(else_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(else_if_block
|
||||||
|
(else_if_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(element
|
||||||
|
(start_tag) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(element
|
||||||
|
(self_closing_tag) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
|
||||||
|
; (if_end) @name @item
|
||||||
|
|
||||||
|
(each_statement
|
||||||
|
(each_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
|
||||||
|
(snippet_statement
|
||||||
|
(snippet_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(snippet_end) @name @item
|
||||||
|
|
||||||
|
(html_tag) @name @item
|
||||||
|
|
||||||
|
(const_tag) @name @item
|
||||||
|
|
||||||
|
(await_statement
|
||||||
|
(await_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(then_block
|
||||||
|
(then_start) @name
|
||||||
|
) @item
|
||||||
|
|
||||||
|
(catch_block
|
||||||
|
(catch_start) @name
|
||||||
|
) @item
|
Loading…
Add table
Add a link
Reference in a new issue