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
|
@ -11,5 +11,5 @@ name = "Svelte Language Server"
|
|||
language = "Svelte"
|
||||
|
||||
[grammars.svelte]
|
||||
repository = "https://github.com/Himujjal/tree-sitter-svelte"
|
||||
commit = "b08d070e303d2a385d6d0ab3add500f8fa514443"
|
||||
repository = "https://github.com/tree-sitter-grammars/tree-sitter-svelte"
|
||||
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"
|
||||
path_suffixes = ["svelte"]
|
||||
block_comment = ["<!-- ", " -->"]
|
||||
autoclose_before = ";:.,=}])>"
|
||||
autoclose_before = ":\"'}]>"
|
||||
brackets = [
|
||||
{ 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 = false, newline = true, not_in = ["string", "comment"] },
|
||||
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
|
||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
|
||||
{ start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
|
||||
{ start = "!--", end = " --", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = true, not_in = ["string"] },
|
||||
{ start = "'", end = "'", close = true, newline = true, not_in = ["string"] },
|
||||
{ start = "`", end = "`", close = true, newline = true, not_in = ["string"] },
|
||||
]
|
||||
scope_opt_in_language_servers = ["tailwindcss-language-server"]
|
||||
prettier_parser_name = "svelte"
|
||||
|
|
|
@ -1,50 +1,107 @@
|
|||
; Special identifiers
|
||||
;--------------------
|
||||
|
||||
; Treat capitalized tag names as constructors and types
|
||||
((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
|
||||
; comments
|
||||
(comment) @comment
|
||||
|
||||
[
|
||||
(attribute_value)
|
||||
(quoted_attribute_value)
|
||||
] @string
|
||||
; property attribute
|
||||
(attribute_directive) @attribute.function
|
||||
(attribute_identifier) @attribute
|
||||
(attribute_modifier) @attribute.special
|
||||
|
||||
[
|
||||
(text)
|
||||
(raw_text_expr)
|
||||
(raw_text_each)
|
||||
] @none
|
||||
; Style component attributes as @property
|
||||
(start_tag
|
||||
(
|
||||
(tag_name) @_tag_name
|
||||
(#match? @_tag_name "^[A-Z]")
|
||||
)
|
||||
(attribute
|
||||
(attribute_name
|
||||
(attribute_identifier) @tag.property
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
[
|
||||
(special_block_keyword)
|
||||
(then)
|
||||
(as)
|
||||
] @keyword
|
||||
(self_closing_tag
|
||||
(
|
||||
(tag_name) @_tag_name
|
||||
(#match? @_tag_name "^[A-Z]")
|
||||
)
|
||||
(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.delimiter
|
||||
] @tag.punctuation.special
|
||||
|
||||
"=" @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
|
||||
((script_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_name)*)
|
||||
(raw_text) @content)
|
||||
(#not-eq? @_name "lang")
|
||||
(#set! "language" "javascript"))
|
||||
; Match script tags with a lang attribute
|
||||
(script_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_attr_name
|
||||
(#eq? @_attr_name "lang")
|
||||
(quoted_attribute_value
|
||||
(attribute_value) @language
|
||||
)
|
||||
)
|
||||
)
|
||||
(raw_text) @content
|
||||
)
|
||||
|
||||
; match javascript
|
||||
((script_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_name
|
||||
(quoted_attribute_value (attribute_value) @_value)))
|
||||
(raw_text) @content)
|
||||
(#eq? @_name "lang")
|
||||
(#eq? @_value "js")
|
||||
(#set! "language" "javascript"))
|
||||
; Match script tags without a lang attribute
|
||||
(script_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_attr_name
|
||||
)*
|
||||
)
|
||||
(raw_text) @content
|
||||
(#not-any-of? @_attr_name "lang")
|
||||
(#set! language "javascript")
|
||||
)
|
||||
|
||||
; match typescript
|
||||
((script_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_name
|
||||
(quoted_attribute_value (attribute_value) @_value)))
|
||||
(raw_text) @content)
|
||||
(#eq? @_name "lang")
|
||||
(#eq? @_value "ts")
|
||||
(#set! "language" "typescript"))
|
||||
; Match the contents of the script's generics="T extends string" as typescript code
|
||||
;
|
||||
; Disabled for the time-being because tree-sitter is treating the generics
|
||||
; attribute as a top-level typescript statement, where `T extends string` is
|
||||
; not a valid top-level typescript statement.
|
||||
;
|
||||
; (script_element
|
||||
; (start_tag
|
||||
; (attribute
|
||||
; (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
|
||||
(raw_text) @content
|
||||
(#set! "language" "css"))
|
||||
(start_tag
|
||||
(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
|
||||
((style_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_name)*)
|
||||
(raw_text) @content)
|
||||
(#not-eq? @_name "lang")
|
||||
(#set! "language" "css"))
|
||||
; Match style tags without a lang attribute
|
||||
(style_element
|
||||
(start_tag
|
||||
(attribute
|
||||
(attribute_name) @_attr_name
|
||||
)*
|
||||
)
|
||||
(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
|
||||
((style_element
|
||||
(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"))
|
||||
; Downstream TODO: Style highlighting for `style:background="red"` and `style="background: red"` strings
|
||||
; Downstream TODO: Style component comments as markdown
|
||||
|
|
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