From c43120be426d3d40927d6dea8c1e89a528aa6715 Mon Sep 17 00:00:00 2001 From: Alessandro Schena Date: Thu, 18 Sep 2025 17:35:10 +0200 Subject: [PATCH 1/4] feat(languages): add support for the eiffel programming language. --- languages.toml | 13 +++++++ runtime/queries/eiffel/highlights.scm | 54 ++++++++++++++++++++++++++ runtime/queries/eiffel/indents.scm | 30 ++++++++++++++ runtime/queries/eiffel/textobjects.scm | 15 +++++++ 4 files changed, 112 insertions(+) create mode 100644 runtime/queries/eiffel/highlights.scm create mode 100644 runtime/queries/eiffel/indents.scm create mode 100644 runtime/queries/eiffel/textobjects.scm diff --git a/languages.toml b/languages.toml index 3cfdb8a5a70a..f1138bd17b57 100644 --- a/languages.toml +++ b/languages.toml @@ -38,6 +38,7 @@ docker-compose-langserver = { command = "docker-compose-langserver", args = ["-- dot-language-server = { command = "dot-language-server", args = ["--stdio"] } dts-lsp = { command = "dts-lsp" } earthlyls = { command = "earthlyls" } +eiffel-language-server = {command = "eiffel-language-server"} elixir-ls = { command = "elixir-ls", config = { elixirLS.dialyzerEnabled = false } } elm-language-server = { command = "elm-language-server" } elp = { command = "elp", args = ["server"] } @@ -408,6 +409,18 @@ auto-format = true name = "textproto" source = { git = "https://github.com/PorterAtGoogle/tree-sitter-textproto", rev = "568471b80fd8793d37ed01865d8c2208a9fefd1b"} +[[language]] +name = "eiffel" +scope = "source.eiffel" +file-types = ["e"] +comment-token = "--" +roots = [] +language-servers = ["eiffel-language-server"] + +[[grammar]] +name = "eiffel" +source = { git = "https://github.com/imustafin/tree-sitter-eiffel.git", rev = "d934fb44f1d22bb76be6b56a7b2425ab3b1daf8b" } + [[language]] name = "elixir" scope = "source.elixir" diff --git a/runtime/queries/eiffel/highlights.scm b/runtime/queries/eiffel/highlights.scm new file mode 100644 index 000000000000..e218fb89f236 --- /dev/null +++ b/runtime/queries/eiffel/highlights.scm @@ -0,0 +1,54 @@ +["class" "feature" "end" "do" "alias" "convert" + "invariant" "across" "as" "loop" "check" + "if" "attached" "then" "else" "elseif" + "inspect" "when" "then" + "note" "local" "create" "require" "ensure" + "from" "variant" "until" "and" "and then" "or" "or else" "xor" + "detachable" "old" "∀" "∃" "¦" "all" "some" + "implies" "once" (unary_not) "attribute" "agent" "like" "export" "all" +] @keyword + +[ "frozen" "deferred" "inherit" "redefine" "undefine" "rename" "select" ] @keyword.modifier + +(conditional ["if" "elseif" "end"] @keyword.conditional) +(else_part ["else"] @keyword.conditional) +(then_part ["then"] @keyword.conditional) +(conditional_expression ["if" "else" "elseif" "end"] @keyword.conditional) +(else_part_expression ["else"] @keyword.conditional) +(then_part_expression ["then"] @keyword.conditional) + +(quantifier_loop ["∀" "∃" ":" "¦"] @keyword.repeat) +(quantifier_loop_body ["all" "some"] @keyword.repeat) +(iteration ["across" "as"] @keyword.repeat) +(initialization ["from"] @keyword.repeat) +(exit_condition ["until"] @keyword.repeat) +(loop (invariant "invariant" @keyword.repeat)) +(loop ["⟳" ":" "¦" "⟲"]@keyword.repeat) +(loop "end" @keyword.repeat) +(loop_body ["loop"] @keyword.repeat) +(variant ["variant"] @keyword.repeat) + +[["(" ")" "[" "]" "<<" ">>"]] @punctuation.bracket +[["," ":"]] @punctuation.delimiter +[[(unary) ":=" (binary_caret) (binary_mul_div) (binary_plus_minus) + (binary_comparison) (binary_and) (binary_or) (binary_implies) + (comparison)]] @operator +[(result)] @variable.builtin +(anchored (call (_) @variable)) +[(verbatim_string) (basic_manifest_string)] @string +[(integer_constant) (real_constant)] @constant.numeric +[(boolean_constant)] @constant.boolean +[(void) (current)] @constant +(extended_feature_name (identifier) @function.method) + +(iteration (identifier) @variable) +(quantifier_loop (identifier) @variable) +(entity_declaration_group (identifier) @variable) +[ + (class_name) +] @type + +(extended_feature_name (identifier) @function) + +[ (comment) ] @comment +[(header_comment)] @comment.documentation diff --git a/runtime/queries/eiffel/indents.scm b/runtime/queries/eiffel/indents.scm new file mode 100644 index 000000000000..8b2cfad13f15 --- /dev/null +++ b/runtime/queries/eiffel/indents.scm @@ -0,0 +1,30 @@ +[ + (class_declaration) + (feature_declaration) + (feature_body) + (notes) + (precondition) + (local_declarations) + (postcondition) + (check) + (initialization) + (iteration) + (loop) + (quantifier_loop) + (then_part) + (else_part) + (then_part_expression) + (else_part_expression) + (multi_branch) +] @indent.begin +(exit_condition) @indent.branch +(loop_body) @indent.branch +(variant) @indent.branch +(invariant) @indent.branch +(loop "end" @indent.branch) +(class_declaration "class" @indent.branch) +(check "end" @indent.branch) +(class_declaration "end" @indent.branch) +(feature_clause "feature" @indent.branch) +(inheritance "inherit" @indent.branch) +(creation_clause "create" @indent.branch) diff --git a/runtime/queries/eiffel/textobjects.scm b/runtime/queries/eiffel/textobjects.scm new file mode 100644 index 000000000000..34693a029773 --- /dev/null +++ b/runtime/queries/eiffel/textobjects.scm @@ -0,0 +1,15 @@ +[ + (comment)+ + (header_comment)+ +] @comment.around +[ + (comment) + (header_comment) +] @comment.inside +(formal_arguments) @parameter.around +(entity_declaration_group) @parameter.inside +(attribute_or_routine) @function.around +(feature_body) @function.inside +(class_declaration) @class.around +(feature_clause) @class.inside + From f594f77cbf12323d6eedfea1797b82256dfcc6c6 Mon Sep 17 00:00:00 2001 From: Alessandro Schena Date: Mon, 22 Sep 2025 16:32:31 +0200 Subject: [PATCH 2/4] fix(lang-eiffel): correct the queries' syntax --- book/src/generated/lang-support.md | 1 + runtime/queries/eiffel/highlights.scm | 142 ++++++++++++++++++-------- runtime/queries/eiffel/indents.scm | 44 ++++---- 3 files changed, 121 insertions(+), 66 deletions(-) diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index 86cc78901c0d..926ae25f0f6c 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -57,6 +57,7 @@ | earthfile | ✓ | ✓ | ✓ | | | `earthlyls` | | edoc | ✓ | | | | | | | eex | ✓ | | | | | | +| eiffel | ✓ | ✓ | ✓ | | | `eiffel-language-server` | | ejs | ✓ | | | | | | | elisp | ✓ | | | ✓ | | | | elixir | ✓ | ✓ | ✓ | ✓ | ✓ | `elixir-ls`, `expert` | diff --git a/runtime/queries/eiffel/highlights.scm b/runtime/queries/eiffel/highlights.scm index e218fb89f236..90b0cfdbf9d5 100644 --- a/runtime/queries/eiffel/highlights.scm +++ b/runtime/queries/eiffel/highlights.scm @@ -1,54 +1,108 @@ -["class" "feature" "end" "do" "alias" "convert" - "invariant" "across" "as" "loop" "check" - "if" "attached" "then" "else" "elseif" - "inspect" "when" "then" - "note" "local" "create" "require" "ensure" - "from" "variant" "until" "and" "and then" "or" "or else" "xor" - "detachable" "old" "∀" "∃" "¦" "all" "some" - "implies" "once" (unary_not) "attribute" "agent" "like" "export" "all" -] @keyword - -[ "frozen" "deferred" "inherit" "redefine" "undefine" "rename" "select" ] @keyword.modifier - -(conditional ["if" "elseif" "end"] @keyword.conditional) -(else_part ["else"] @keyword.conditional) -(then_part ["then"] @keyword.conditional) -(conditional_expression ["if" "else" "elseif" "end"] @keyword.conditional) -(else_part_expression ["else"] @keyword.conditional) -(then_part_expression ["then"] @keyword.conditional) - -(quantifier_loop ["∀" "∃" ":" "¦"] @keyword.repeat) -(quantifier_loop_body ["all" "some"] @keyword.repeat) -(iteration ["across" "as"] @keyword.repeat) -(initialization ["from"] @keyword.repeat) -(exit_condition ["until"] @keyword.repeat) -(loop (invariant "invariant" @keyword.repeat)) -(loop ["⟳" ":" "¦" "⟲"]@keyword.repeat) -(loop "end" @keyword.repeat) -(loop_body ["loop"] @keyword.repeat) -(variant ["variant"] @keyword.repeat) - -[["(" ")" "[" "]" "<<" ">>"]] @punctuation.bracket -[["," ":"]] @punctuation.delimiter -[[(unary) ":=" (binary_caret) (binary_mul_div) (binary_plus_minus) - (binary_comparison) (binary_and) (binary_or) (binary_implies) - (comparison)]] @operator -[(result)] @variable.builtin +[ + "alias" + "convert" + "inherit" + "redefine" + "undefine" + "rename" + "select" + "note" + "create" +] @keyword.control.import + +["export"] @keyword.control.export + +[ + "do" + "end" + "once" + "attribute" +] @keyword.control + +[ + "class" + "local" +] @keyword.storage.type + +[ + "feature" + "agent" +] @keyword.function + +[ + "frozen" + "deferred" + "detachable" + "expanded" + "attached" + "old" + "like" +] @keyword.storage.modifier + +(conditional ["if" "elseif" "end"] @keyword.control.conditional) +(else_part ["else"] @keyword.control.conditional) +(then_part ["then"] @keyword.control.conditional) + +(conditional_expression ["if" "else" "elseif" "end"] @keyword.control.conditional) +(else_part_expression ["else"] @keyword.control.conditional) +(then_part_expression ["then"] @keyword.control.conditional) + +(multi_branch "inspect" @keyword.control.conditional) +(when_part ["when" "then"] @keyword.control.conditional) + +(multi_branch_expression "inspect" @keyword.control.conditional) +(when_part_expression ["when" "then"] @keyword.control.conditional) + +(quantifier_loop ["∀" "∃" ":" "¦"] @keyword.control.repeat) +(quantifier_loop_body ["all" "some"] @keyword.control.repeat) +(iteration ["across" "as"] @keyword.control.repeat) +(initialization "from" @keyword.control.repeat) +(exit_condition "until" @keyword.control.repeat) +(loop_body "loop" @keyword.control.repeat) +(variant "variant" @keyword.control.repeat) +(loop (invariant "invariant" @keyword.control.repeat)) +(loop ["⟳" ":" "¦" "⟲"]@keyword.control.repeat) +(loop "end" @keyword.control.repeat) + +[ + "require" + "ensure" + "invariant" + "check" +] @keyword.control.exception + +["(" ")" "[" "]" "<<" ">>"] @punctuation.bracket +["," ":" ";"] @punctuation.delimiter + +[ + (unary) + ":=" + (binary_caret) + (binary_mul_div) + (binary_plus_minus) + (binary_comparison) + (binary_and) + (binary_or) + (binary_implies) + (comparison) + (unary_not) +] @operator + +(result) @variable.builtin (anchored (call (_) @variable)) [(verbatim_string) (basic_manifest_string)] @string [(integer_constant) (real_constant)] @constant.numeric -[(boolean_constant)] @constant.boolean -[(void) (current)] @constant +(boolean_constant) @constant.builtin.boolean +(void) @constant.builtin +(current) @variable.builtin (extended_feature_name (identifier) @function.method) (iteration (identifier) @variable) (quantifier_loop (identifier) @variable) (entity_declaration_group (identifier) @variable) -[ - (class_name) -] @type -(extended_feature_name (identifier) @function) +(class_name) @type +(formal_generic) @type.parameter -[ (comment) ] @comment -[(header_comment)] @comment.documentation +(comment) @comment.line +(header_comment) @comment.line.documentation diff --git a/runtime/queries/eiffel/indents.scm b/runtime/queries/eiffel/indents.scm index 8b2cfad13f15..5be4cb427933 100644 --- a/runtime/queries/eiffel/indents.scm +++ b/runtime/queries/eiffel/indents.scm @@ -1,30 +1,30 @@ [ + (notes) (class_declaration) + (inheritance) + (feature_adaptation) + (creation_clause) + (converters) + (feature_declaration) - (feature_body) - (notes) + + (attribute_or_routine) + (precondition) (local_declarations) - (postcondition) + (feature_body) + (check) - (initialization) - (iteration) + (multi_branch) + (multi_branch_expression) + (conditional) + (conditional_expression) (loop) (quantifier_loop) - (then_part) - (else_part) - (then_part_expression) - (else_part_expression) - (multi_branch) -] @indent.begin -(exit_condition) @indent.branch -(loop_body) @indent.branch -(variant) @indent.branch -(invariant) @indent.branch -(loop "end" @indent.branch) -(class_declaration "class" @indent.branch) -(check "end" @indent.branch) -(class_declaration "end" @indent.branch) -(feature_clause "feature" @indent.branch) -(inheritance "inherit" @indent.branch) -(creation_clause "create" @indent.branch) + (iteration) + + (postcondition) + (rescue) + + (invariant) +] @indent From 24c5d4335486c5d32be08fc4cf53c86d439c4df3 Mon Sep 17 00:00:00 2001 From: Alessandro Schena Date: Tue, 23 Sep 2025 23:33:52 +0200 Subject: [PATCH 3/4] fix: link to eiffel grammar (remove ext .git) --- languages.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/languages.toml b/languages.toml index f1138bd17b57..a1ecf45f3f6e 100644 --- a/languages.toml +++ b/languages.toml @@ -419,7 +419,7 @@ language-servers = ["eiffel-language-server"] [[grammar]] name = "eiffel" -source = { git = "https://github.com/imustafin/tree-sitter-eiffel.git", rev = "d934fb44f1d22bb76be6b56a7b2425ab3b1daf8b" } +source = { git = "https://github.com/imustafin/tree-sitter-eiffel", rev = "d934fb44f1d22bb76be6b56a7b2425ab3b1daf8b" } [[language]] name = "elixir" From 48cbe95778243885495ebad4176f5477fc5ebf60 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 4 Oct 2025 15:08:19 -0400 Subject: [PATCH 4/4] Update languages.toml --- languages.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/languages.toml b/languages.toml index a1ecf45f3f6e..f2595e26a40d 100644 --- a/languages.toml +++ b/languages.toml @@ -414,7 +414,6 @@ name = "eiffel" scope = "source.eiffel" file-types = ["e"] comment-token = "--" -roots = [] language-servers = ["eiffel-language-server"] [[grammar]]