diff --git a/extension.toml b/extension.toml index 935ecb6..ac42246 100644 --- a/extension.toml +++ b/extension.toml @@ -11,5 +11,6 @@ name = "Svelte Language Server" language = "Svelte" [grammars.svelte] -repository = "https://github.com/tree-sitter-grammars/tree-sitter-svelte" -commit = "3f06f705410683adb17d146b5eca28c62fe81ba6" +repository = "https://github.com/themixednuts/tree-sitter-htmlx" +commit = "c9b9cc35709fff494a3a9e41cd9471b633649e45" +path = "crates/tree-sitter-svelte" diff --git a/languages/svelte/brackets.scm b/languages/svelte/brackets.scm index 0a7b509..f230c5b 100644 --- a/languages/svelte/brackets.scm +++ b/languages/svelte/brackets.scm @@ -1,9 +1,7 @@ ("<" @open ">" @close) ("{" @open "}" @close) -("'" @open "'" @close) -("\"" @open "\"" @close) +(("'" @open "'" @close) (#set! rainbow.exclude)) +(("\"" @open "\"" @close) (#set! rainbow.exclude)) ("(" @open ")" @close) -; ("[" @open "]" @close) -; ("`" @open "`" @close) ((element (start_tag) @open [(end_tag) (erroneous_end_tag)] @close) (#set! newline.only)) diff --git a/languages/svelte/folds.scm b/languages/svelte/folds.scm new file mode 100644 index 0000000..058bcdf --- /dev/null +++ b/languages/svelte/folds.scm @@ -0,0 +1,15 @@ +[ + (comment) + (element) + (if_block) + (else_if_clause) + (else_clause) + (each_block) + (await_block) + (await_pending) + (await_branch) + (await_branch_children) + (key_block) + (orphan_branch) + (snippet_block) +] @fold diff --git a/languages/svelte/highlights.scm b/languages/svelte/highlights.scm index cd3a089..424fb68 100755 --- a/languages/svelte/highlights.scm +++ b/languages/svelte/highlights.scm @@ -1,108 +1,136 @@ +; Tag names +(tag_name) @tag -; comments +; Erroneous/mismatched end tags +(erroneous_end_tag_name) @tag + +; DOCTYPE declaration +(doctype) @constant + +; Attribute names +(attribute_name) @attribute + +; Attribute values +(attribute_value) @string +(quoted_attribute_value) @string + +; Comments (comment) @comment -; property attribute -(attribute_directive) @attribute.function -(attribute_identifier) @attribute -(attribute_modifier) @attribute.special - -; Style component attributes as @property -(start_tag - ( - (tag_name) @_tag_name - (#match? @_tag_name "^[A-Z]") - ) - (attribute - (attribute_name - (attribute_identifier) @tag.property - ) - ) -) - -; Style self-closing component attributes as @tag.property -(self_closing_tag - ( - (tag_name) @_tag_name - (#match? @_tag_name "^[A-Z]") - ) - (attribute - (attribute_name - (attribute_identifier) @tag.property - ) - ) -) - - -; 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]") -) +; Character entities +(entity) @string.special + +; Text content +(text) @text +; Raw text in script/style +(raw_text) @text.literal + +; HTML punctuation [ "<" ">" "" -] @tag.punctuation.bracket - - -[ - "{" - "}" ] @punctuation.bracket -[ - "|" -] @punctuation.delimiter - - -[ - "@" - "#" - ":" - "/" -] @tag.punctuation.special - -"=" @operator +"=" @punctuation.delimiter +; Component tags (PascalCase) +((tag_name) @type (#match? @type "^[A-Z]")) -; Treating (if, each, ...) as a keyword inside of blocks -; like {#if ...} or {#each ...} -(block_start_tag - tag: _ @keyword -) +; Namespaced tags (svelte:component, svelte:self, etc.) +(tag_name + namespace: (tag_namespace) @keyword + ":" @punctuation.delimiter + name: (tag_local_name) @tag) -(block_tag - tag: _ @keyword -) +; Tag member access (Foo.Bar) +(tag_name + object: (tag_member) @type + "." @punctuation.delimiter + property: (tag_member) @tag) -(block_end_tag - tag: _ @keyword -) +; Directives (on:click, bind:value, etc.) +(attribute_directive) @keyword +(attribute_name ":" @punctuation.delimiter) +(attribute_identifier) @property +(attribute_modifier) @attribute +(attribute_modifiers "|" @punctuation.delimiter) -(expression_tag - tag: _ @keyword -) +; Expressions +(expression) @embedded -; Style quoted string attribute values -(quoted_attribute_value) @string +; Shorthand/spread attributes — content only, braces fall through to "{" "}" rule +(shorthand_attribute content: (_) @variable) +; Curly braces (expression context) +[ + "{" + "}" +] @punctuation.bracket -; Highlight the `as` keyword in each blocks -(each_start - ("as") @tag.keyword -) +"|" @punctuation.delimiter +; Comments inside tag attribute lists +(tag_comment kind: (line_comment) @comment) +(tag_comment kind: (block_comment) @comment) -; Highlight the snippet name as a function -; (e.g. {#snippet foo(bar)} -(snippet_name) @function +; Block keywords +[ + "if" + "each" + "await" + "key" + "snippet" + "else" + "html" + "debug" + "const" + "render" + "attach" + "as" +] @keyword.control + +; Block end keywords ({/if}, {/each}, etc.) +(block_keyword) @keyword.control +(declaration_kind) @keyword.control + +; Block delimiters +(block_open) @punctuation.bracket +(block_close) @punctuation.bracket + +(shorthand_kind) @keyword.control +(branch_kind) @keyword.control + +(expression_value) @embedded + +; 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 (e.g. { #if ...} with space before sigil) +(block_sigil) @keyword.control + +; Snippet/render punctuation +["(" ")" ","] @punctuation.delimiter diff --git a/languages/svelte/indents.scm b/languages/svelte/indents.scm index 8edbf93..ffcdc28 100755 --- a/languages/svelte/indents.scm +++ b/languages/svelte/indents.scm @@ -1,20 +1,13 @@ [ (element) - (if_statement) - (each_statement) - (await_statement) - (snippet_statement) - (script_element) - (style_element) + (if_block) + (each_block) + (await_block) + (key_block) + (snippet_block) (start_tag ">" @end) (self_closing_tag "/>" @end) (element (start_tag) @start [(end_tag) (erroneous_end_tag)]? @end) - (script_element - (start_tag) @start - [(end_tag) (erroneous_end_tag)]? @end) - (style_element - (start_tag) @start - [(end_tag) (erroneous_end_tag)]? @end) ] @indent diff --git a/languages/svelte/injections.scm b/languages/svelte/injections.scm index 7195cc4..70df30e 100755 --- a/languages/svelte/injections.scm +++ b/languages/svelte/injections.scm @@ -1,89 +1,196 @@ -; ; injections.scm -; ; -------------- - -; Add support for comment language injections -((comment) @content - (#set! "language" "comment") - ) - -; 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 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 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