From b844e8cdc7ad6ae08a5b916bdc791b6785c2f1e4 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 10 Oct 2024 20:40:10 -0700 Subject: [PATCH 1/6] First pass at adding a language mode for elixir --- core/modes/language_modes.py | 1 + lang/elixir/elixir.py | 161 +++++++++++++++++++++++++++++++++++ lang/elixir/elixir.talon | 46 ++++++++++ 3 files changed, 208 insertions(+) create mode 100644 lang/elixir/elixir.py create mode 100644 lang/elixir/elixir.talon diff --git a/core/modes/language_modes.py b/core/modes/language_modes.py index 936c147b12..f069fd9600 100644 --- a/core/modes/language_modes.py +++ b/core/modes/language_modes.py @@ -20,6 +20,7 @@ "javascript": "js", "javascriptreact": "jsx", # "json": "json", + "elixir": "ex", "kotlin": "kt", "lua": "lua", "markdown": "md", diff --git a/lang/elixir/elixir.py b/lang/elixir/elixir.py new file mode 100644 index 0000000000..3e4063ac7e --- /dev/null +++ b/lang/elixir/elixir.py @@ -0,0 +1,161 @@ +from talon import Context, Module, actions, settings + +ctx = Context() +mod = Module() +ctx.matches = r""" +code.language: elixir +""" + +# Elixir keywords and constructs +ctx.lists["user.code_keyword"] = { + "def": "def ", + "def p": "defp ", + "do": "do ", + "end": "end", + "if": "if ", + "else": "else ", + "cond": "cond ", + "case": "case ", + "when": "when ", + "f n": "fn ", + "receive": "receive ", + "after": "after ", + "try": "try ", + "catch": "catch ", + "rescue": "rescue ", + "raise": "raise ", + "with": "with ", + "unless": "unless ", + "import": "import ", + "alias": "alias ", + "require": "require ", + "use": "use ", +} + + +@ctx.action_class("user") +class UserActions: + def code_comment_line_prefix(): + actions.insert("# ") + + def code_operator_lambda(): + actions.auto_insert("->") + + def code_operator_assignment(): + actions.auto_insert(" = ") + + def code_operator_addition(): + actions.auto_insert(" + ") + + def code_operator_subtraction(): + actions.auto_insert(" - ") + + def code_operator_multiplication(): + actions.auto_insert(" * ") + + def code_operator_division(): + actions.auto_insert(" / ") + + def code_operator_equal(): + actions.auto_insert(" == ") + + def code_operator_not_equal(): + actions.auto_insert(" != ") + + def code_operator_greater_than(): + actions.auto_insert(" > ") + + def code_operator_greater_than_or_equal_to(): + actions.auto_insert(" >= ") + + def code_operator_less_than(): + actions.auto_insert(" < ") + + def code_operator_less_than_or_equal_to(): + actions.auto_insert(" <= ") + + def code_operator_and(): + actions.auto_insert(" and ") + + def code_operator_or(): + actions.auto_insert(" or ") + + def code_self(): + actions.auto_insert("self") + + def code_insert_null(): + actions.insert("nil") + + def code_insert_is_null(): + actions.insert(" == nil") + + def code_insert_is_not_null(): + actions.insert(" != nil") + + def code_state_if(): + actions.user.insert_between("if ", " do\nend") + + def code_state_else_if(): + actions.user.insert_between("else if ", " do\nend") + + def code_state_else(): + actions.insert("else\nend") + actions.key("enter") + + def code_state_case(): + actions.user.insert_between("case ", " do\nend") + + def code_state_for(): + actions.user.insert_between("for ", " do\nend") + + def code_state_while(): + actions.user.insert_between("while ", " do\nend") + + def code_define_class(): + # Elixir doesn't have classes, so this is not applicable + pass + + def code_state_return(): + # Elixir functions automatically return the last evaluated expression + pass + + def code_insert_function(text: str, selection: str): + text += f"({selection or ''})" + actions.user.paste(text) + actions.edit.left() + + def code_default_function(text: str): + result = "def {}".format( + actions.user.formatted_text( + text, settings.get("user.code_protected_function_formatter") + ) + ) + actions.user.code_insert_function(result, None) + + def code_public_function(text: str): + actions.user.code_default_function(text) + + def code_private_function(text: str): + """Inserts private function declaration""" + result = "defp {}".format( + actions.user.formatted_text( + text, settings.get("user.code_private_function_formatter") + ) + ) + actions.user.code_insert_function(result, None) + + def code_import_module(text: str): + actions.auto_insert("import ") + actions.insert(text) + + def code_alias_module(text: str): + actions.auto_insert("alias ") + actions.insert(text) + + def code_require_module(text: str): + actions.auto_insert("require ") + actions.insert(text) + + def code_use_module(text: str): + actions.auto_insert("use ") + actions.insert(text) diff --git a/lang/elixir/elixir.talon b/lang/elixir/elixir.talon new file mode 100644 index 0000000000..6484b320fc --- /dev/null +++ b/lang/elixir/elixir.talon @@ -0,0 +1,46 @@ +code.language: elixir +- +tag(): user.code_functional +tag(): user.code_concurrent + +tag(): user.code_comment_line +tag(): user.code_data_bool +tag(): user.code_data_null +tag(): user.code_functions +tag(): user.code_keywords +tag(): user.code_libraries +tag(): user.code_operators_array +tag(): user.code_operators_assignment +tag(): user.code_operators_math +tag(): user.code_operators_lambda + +settings(): + user.code_private_function_formatter = "snake_case" + user.code_public_function_formatter = "snake_case" + user.code_private_variable_formatter = "snake_case" + user.code_public_variable_formatter = "snake_case" + +# Elixir-specific grammars +state def: "def " +state defp: "defp " +state if: "if " +state else: "else" +state case: "case " +state cond: "cond do" +state try: "try do" +state rescue: "rescue" +state after: "after" +state end: "end" + +# Elixir-specific keywords and symbols +true: "true" +false: "false" +nil: "nil" + +[state] raise {user.elixir_exception}: + user.insert_between("raise ", "") + +[state] rescue {user.elixir_exception}: "rescue {elixir_exception}" + +comment line: user.code_comment_line_prefix() +comment block: user.code_comment_block_prefix() From 257e9d3e04b70188d45799af42c27590bd424ad4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 03:41:11 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- lang/elixir/elixir.talon | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lang/elixir/elixir.talon b/lang/elixir/elixir.talon index 6484b320fc..0d69c45e81 100644 --- a/lang/elixir/elixir.talon +++ b/lang/elixir/elixir.talon @@ -37,8 +37,7 @@ true: "true" false: "false" nil: "nil" -[state] raise {user.elixir_exception}: - user.insert_between("raise ", "") +[state] raise {user.elixir_exception}: user.insert_between("raise ", "") [state] rescue {user.elixir_exception}: "rescue {elixir_exception}" From e262985b874a43eed94099ea280882451559d631 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Fri, 11 Oct 2024 08:18:39 -0700 Subject: [PATCH 3/6] Add defmodule to keywords --- lang/elixir/elixir.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/elixir/elixir.py b/lang/elixir/elixir.py index 3e4063ac7e..9a90a3d375 100644 --- a/lang/elixir/elixir.py +++ b/lang/elixir/elixir.py @@ -10,6 +10,7 @@ ctx.lists["user.code_keyword"] = { "def": "def ", "def p": "defp ", + "def module": "defmodule ", "do": "do ", "end": "end", "if": "if ", From cd7de8054aa21ec19ae4647ed2b92a5d921be324 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Fri, 11 Oct 2024 09:07:15 -0700 Subject: [PATCH 4/6] Add elixir |> operator --- lang/elixir/elixir.talon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lang/elixir/elixir.talon b/lang/elixir/elixir.talon index 0d69c45e81..e0c436aeac 100644 --- a/lang/elixir/elixir.talon +++ b/lang/elixir/elixir.talon @@ -32,6 +32,8 @@ state rescue: "rescue" state after: "after" state end: "end" +op pipe: " |> " + # Elixir-specific keywords and symbols true: "true" false: "false" From 6b99c2acbcbea35c9286f78cd24095566f9236e2 Mon Sep 17 00:00:00 2001 From: Joshua Aresty Date: Thu, 17 Oct 2024 17:34:16 -0700 Subject: [PATCH 5/6] Respond to pull request feedback --- core/file_extension/file_extension.py | 1 + lang/elixir/elixir.py | 6 ++++++ lang/elixir/elixir.talon | 6 ------ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/file_extension/file_extension.py b/core/file_extension/file_extension.py index 1a75e76c42..340790e5cc 100644 --- a/core/file_extension/file_extension.py +++ b/core/file_extension/file_extension.py @@ -7,6 +7,7 @@ _file_extensions_defaults = { "dot pie": ".py", + "dot elixir": ".ex", "dot talon": ".talon", "dot mark down": ".md", "dot shell": ".sh", diff --git a/lang/elixir/elixir.py b/lang/elixir/elixir.py index 9a90a3d375..8387feccf8 100644 --- a/lang/elixir/elixir.py +++ b/lang/elixir/elixir.py @@ -84,6 +84,12 @@ def code_operator_or(): def code_self(): actions.auto_insert("self") + def code_insert_true(): + actions.auto_insert("true") + + def code_insert_false(): + actions.auto_insert("false") + def code_insert_null(): actions.insert("nil") diff --git a/lang/elixir/elixir.talon b/lang/elixir/elixir.talon index e0c436aeac..286a3241c2 100644 --- a/lang/elixir/elixir.talon +++ b/lang/elixir/elixir.talon @@ -35,13 +35,7 @@ state end: "end" op pipe: " |> " # Elixir-specific keywords and symbols -true: "true" -false: "false" -nil: "nil" [state] raise {user.elixir_exception}: user.insert_between("raise ", "") [state] rescue {user.elixir_exception}: "rescue {elixir_exception}" - -comment line: user.code_comment_line_prefix() -comment block: user.code_comment_block_prefix() From 4199d9a319d48eb83a4a4986b7eec0b0ed83a582 Mon Sep 17 00:00:00 2001 From: Phil Cohen Date: Fri, 18 Oct 2024 14:33:25 -0700 Subject: [PATCH 6/6] Update lang/elixir/elixir.talon --- lang/elixir/elixir.talon | 1 - 1 file changed, 1 deletion(-) diff --git a/lang/elixir/elixir.talon b/lang/elixir/elixir.talon index 286a3241c2..ee5052b6e5 100644 --- a/lang/elixir/elixir.talon +++ b/lang/elixir/elixir.talon @@ -35,7 +35,6 @@ state end: "end" op pipe: " |> " # Elixir-specific keywords and symbols - [state] raise {user.elixir_exception}: user.insert_between("raise ", "") [state] rescue {user.elixir_exception}: "rescue {elixir_exception}"