From 45560453450e22c035e2d20511368602da303cc6 Mon Sep 17 00:00:00 2001 From: deathaxe Date: Mon, 26 Aug 2024 19:06:50 +0200 Subject: [PATCH] Initial support for JSX tags Resolves #148 Fixes #218 --- CoffeeScript.sublime-syntax | 180 +++++++++++++++++++++++++++++++++ Comments JSX.tmPreferences | 26 +++++ tests/syntax_test_scope.coffee | 46 +++++++++ 3 files changed, 252 insertions(+) create mode 100644 Comments JSX.tmPreferences diff --git a/CoffeeScript.sublime-syntax b/CoffeeScript.sublime-syntax index 21a2282..7eb2cc4 100644 --- a/CoffeeScript.sublime-syntax +++ b/CoffeeScript.sublime-syntax @@ -32,6 +32,7 @@ contexts: - include: classes - include: keywords - include: functions + - include: jsx-tags - include: expressions expressions: @@ -573,6 +574,171 @@ contexts: pop: 1 - include: script +###[ JSX TAGS ]################################################################ + + jsx-tags: + - match: (<)(?:({{component_names}})|({{tag_names}}))(?=\s|/?>) + captures: + 1: punctuation.definition.tag.begin.coffee + 2: entity.name.tag.component.coffee + 3: entity.name.tag.coffee + push: + - jsx-meta + - jsx-tag-open-body + + jsx-meta: + - meta_include_prototype: false + - meta_scope: meta.jsx.coffee + - include: immediately-pop + + jsx-body: + - match: () + captures: + 1: punctuation.definition.tag.begin.coffee + 2: entity.name.tag.component.coffee + 3: entity.name.tag.coffee + set: jsx-tag-close-body + - match: (<)(?:({{component_names}})|({{tag_names}}))(?=\s|/?>) + captures: + 1: punctuation.definition.tag.begin.coffee + 2: entity.name.tag.component.coffee + 3: entity.name.tag.coffee + push: jsx-tag-open-body + - include: jsx-text-interpolations + + jsx-tag-close-body: + - meta_include_prototype: false + - meta_scope: meta.tag.coffee + - match: /?> + scope: punctuation.definition.tag.end.coffee + pop: 1 + + jsx-tag-open-body: + - meta_include_prototype: false + - meta_scope: meta.tag.coffee + - match: /> + scope: punctuation.definition.tag.end.coffee + pop: 1 + - match: \> + scope: punctuation.definition.tag.end.coffee + set: jsx-body + - match: '{{attribute_name_start}}' + push: + - jsx-tag-attribute-meta + - jsx-tag-attribute-assignment + - jsx-tag-attribute-name + + jsx-tag-attribute-name: + - meta_scope: entity.other.attribute-name.coffee + - include: jsx-string-interpolations + - match: '{{attribute_name_break}}' + pop: 1 + - match: '["''`<]' + scope: invalid.illegal.attribute-name.coffee + + jsx-tag-attribute-meta: + - meta_include_prototype: false + - meta_scope: meta.attribute-with-value.coffee + - include: immediately-pop + + jsx-tag-attribute-assignment: + - meta_include_prototype: false + - match: = + scope: punctuation.separator.key-value.coffee + set: jsx-tag-attribute-value + - include: else-pop + + jsx-tag-attribute-value: + - meta_include_prototype: false + - match: \" + scope: punctuation.definition.string.begin.coffee + set: jsx-tag-attribute-value-double-quoted-content + - match: \' + scope: punctuation.definition.string.begin.coffee + set: jsx-tag-attribute-value-single-quoted-content + - match: '{{unquoted_attribute_start}}' + set: jsx-tag-attribute-value-unquoted-content + - include: else-pop + + jsx-tag-attribute-value-double-quoted-content: + # See the top of this file for why prototype is excluded + - meta_include_prototype: false + - meta_scope: meta.string.coffee string.quoted.double.coffee + - match: \" + scope: punctuation.definition.string.end.coffee + pop: 1 + - include: jsx-string-interpolations + + jsx-tag-attribute-value-single-quoted-content: + # See the top of this file for why prototype is excluded + - meta_include_prototype: false + - meta_scope: meta.string.coffee string.quoted.single.coffee + - match: \' + scope: punctuation.definition.string.end.coffee + pop: 1 + - include: jsx-string-interpolations + + jsx-tag-attribute-value-unquoted-content: + # See the top of this file for why prototype is excluded + - meta_include_prototype: false + - meta_content_scope: meta.string.coffee string.unquoted.coffee + - include: jsx-string-interpolations + - match: '{{unquoted_attribute_break}}' + pop: 1 + - match: '["''`<]' + scope: invalid.illegal.attribute-value.coffee + + jsx-string-interpolations: + - match: \{# + scope: punctuation.definition.comment.begin.coffee + push: jsx-string-comment-body + - match: \{ + scope: punctuation.section.interpolation.begin.coffee + push: jsx-string-interpolation-body + + jsx-string-comment-body: + # required to support "toggle_comment" + - clear_scopes: 1 + - meta_scope: meta.interpolation.coffee comment.block.coffee + - include: jsx-text-comment-body + + jsx-string-interpolation-body: + - clear_scopes: 1 + - meta_scope: meta.interpolation.coffee + - meta_content_scope: source.coffee.embedded.jsx + - include: jsx-text-interpolation-body + + jsx-text-interpolations: + - match: \{# + scope: punctuation.definition.comment.begin.coffee + push: jsx-text-comment-body + - match: \{ + scope: punctuation.section.interpolation.begin.coffee + push: jsx-text-interpolation-body + + jsx-text-comment-body: + # required to support "toggle_comment" + - meta_scope: meta.interpolation.coffee comment.block.coffee + - match: \} + scope: punctuation.definition.comment.end.coffee + pop: 1 + + jsx-text-interpolation-body: + - meta_scope: meta.interpolation.coffee + - meta_content_scope: source.coffee.embedded.jsx + - match: \} + scope: punctuation.section.interpolation.end.coffee + pop: 1 + - match: \# + scope: punctuation.definition.comment.coffee + push: jsx-line-comment-body + - include: script + + jsx-line-comment-body: + - meta_scope: comment.line.number-sign.coffee + - match: $\n?|(?=}) + pop: 1 + ###[ VARIABLES ]############################################################### instance-variables: @@ -596,4 +762,18 @@ contexts: variables: + ascii_space: '\t\n\f ' + identifier: '[a-zA-Z\$_]\w*' + + component_names: '[A-Z][[:alnum:]_.-]*' + tag_names: '[[:alpha:]][[:alnum:]_.-]*' + + # https://html.spec.whatwg.org/multipage/syntax.coffee#attributes-2 + attribute_name_break_char: '[{{ascii_space}}=/>]' + attribute_name_break: (?={{attribute_name_break_char}}) + attribute_name_start: (?=[^{{attribute_name_break_char}}]) + + # https://html.spec.whatwg.org/multipage/syntax.coffee#syntax-attribute-value + unquoted_attribute_break: (?=[{{ascii_space}}]|/?>) + unquoted_attribute_start: (?=[^{{ascii_space}}=>]) diff --git a/Comments JSX.tmPreferences b/Comments JSX.tmPreferences new file mode 100644 index 0000000..6448f16 --- /dev/null +++ b/Comments JSX.tmPreferences @@ -0,0 +1,26 @@ + + + + + scope + source.coffee meta.jsx, source.coffee meta.jsx meta.interpolation comment.line + settings + + shellVariables + + + name + TM_COMMENT_START + value + {# + + + name + TM_COMMENT_END + value + } + + + + + diff --git a/tests/syntax_test_scope.coffee b/tests/syntax_test_scope.coffee index 051c42e..ba729f1 100644 --- a/tests/syntax_test_scope.coffee +++ b/tests/syntax_test_scope.coffee @@ -561,3 +561,49 @@ class App.Router extends Snakeskin.Router @variable # ^^^^^^^^^ variable.other.readwrite.instance.coffee # ^ punctuation.definition.variable.coffee + +###[ JSX ]##################################################################### + + +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.jsx.coffee meta.tag.coffee +# ^ punctuation.definition.tag.begin.coffee +# ^^^^^^^^^ entity.name.tag.component.coffee +# ^^^^^^^^^^^^^^^^^ meta.attribute-with-value.coffee +# ^^^^^^ entity.other.attribute-name.coffee +# ^ punctuation.separator.key-value.coffee +# ^^^ meta.string.coffee string.quoted.double.coffee +# ^^^^^^ meta.string.coffee meta.interpolation.coffee +# ^ punctuation.section.interpolation.begin.coffee +# ^^^^ source.coffee.embedded.jsx variable.other.readwrite.instance.coffee +# ^ punctuation.section.interpolation.end.coffee +# ^ meta.string.coffee string.quoted.double.coffee punctuation.definition.string.end.coffee +# ^ punctuation.definition.tag.end.coffee +

Text {# comment}!

+# ^^^^ meta.jsx.coffee meta.tag.coffee +# ^ punctuation.definition.tag.begin.coffee +# ^^ entity.name.tag.coffee +# ^ punctuation.definition.tag.end.coffee +# ^^^^^ meta.jsx.coffee - meta.interpolation +# ^^^^^^^^^^^ meta.jsx.coffee meta.interpolation.coffee comment.block.coffee +# ^^ punctuation.definition.comment.begin.coffee +# ^ punctuation.definition.comment.end.coffee +# ^ meta.jsx.coffee - meta.interpolation +# ^^^^^ meta.jsx.coffee meta.tag.coffee +# ^^ punctuation.definition.tag.begin.coffee +# ^^ entity.name.tag.coffee +# ^ punctuation.definition.tag.end.coffee +
+# ^^^^^^^^^^^^ meta.jsx.coffee meta.tag.coffee +# ^^ punctuation.definition.tag.begin.coffee +# ^^^^^^^^^ entity.name.tag.component.coffee +# ^ punctuation.definition.tag.end.coffee +# ^ - meta.jsx - meta.tag + + +# ^^ meta.jsx.coffee meta.tag.coffee punctuation.definition.tag.end.coffee +# ^ - meta.jsx - meta.tag