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()