diff --git a/.gitmodules b/.gitmodules index a8e6481ea..01260b847 100644 --- a/.gitmodules +++ b/.gitmodules @@ -84,7 +84,7 @@ shallow = true [submodule "helix-syntax/languages/tree-sitter-elixir"] path = helix-syntax/languages/tree-sitter-elixir - url = https://github.com/IceDragon200/tree-sitter-elixir + url = https://github.com/elixir-lang/tree-sitter-elixir shallow = true [submodule "helix-syntax/languages/tree-sitter-nix"] path = helix-syntax/languages/tree-sitter-nix diff --git a/book/src/themes.md b/book/src/themes.md index a99e3a59e..5a4d04038 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -119,6 +119,7 @@ #### Syntax highlighting - `special` - `path` - `url` + - `symbol` - Erlang/Elixir atoms, Ruby symbols, Clojure keywords - `comment` - Code comments - `line` - Single line comments (`//`) diff --git a/helix-syntax/languages/tree-sitter-elixir b/helix-syntax/languages/tree-sitter-elixir index 295e62a43..f5d7bda54 160000 --- a/helix-syntax/languages/tree-sitter-elixir +++ b/helix-syntax/languages/tree-sitter-elixir @@ -1 +1 @@ -Subproject commit 295e62a43b92cea909cfabe57e8818d177f4857b +Subproject commit f5d7bda543da788bd507b05bd722627dde66c9ec diff --git a/runtime/queries/elixir/highlights.scm b/runtime/queries/elixir/highlights.scm index 6bf93a210..08e09f37a 100644 --- a/runtime/queries/elixir/highlights.scm +++ b/runtime/queries/elixir/highlights.scm @@ -1,125 +1,213 @@ -["when" "and" "or" "not in" "not" "in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword +; The following code originates mostly from +; https://github.com/elixir-lang/tree-sitter-elixir, with minor edits to +; align the captures with helix. The following should be considered +; Copyright 2021 The Elixir Team +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; https://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, +; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; See the License for the specific language governing permissions and +; limitations under the License. -[(true) (false) (nil)] @constant.builtin +; Reserved keywords -(keyword - [(keyword_literal) - ":"] @tag) +["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword -(keyword - (keyword_string - [(string_start) - (string_content) - (string_end)] @tag)) +; Operators -[(atom_literal) - (atom_start) - (atom_content) - (atom_end)] @tag +; * doc string +(unary_operator + operator: "@" @comment.block.documentation + operand: (call + target: (identifier) @comment.block.documentation.__attribute__ + (arguments + [ + (string) @comment.block.documentation + (charlist) @comment.block.documentation + (sigil + quoted_start: _ @comment.block.documentation + quoted_end: _ @comment.block.documentation) @comment.block.documentation + (boolean) @comment.block.documentation + ])) + (#match? @comment.block.documentation.__attribute__ "^(moduledoc|typedoc|doc)$")) -[(comment) - (unused_identifier)] @comment +; * module attribute +(unary_operator + operator: "@" @variable.property + operand: [ + (identifier) @variable.property + (call + target: (identifier) @variable.property) + (boolean) @variable.property + (nil) @variable.property + ]) + +; * capture operator +(unary_operator + operator: "&" + operand: [ + (integer) @operator + (binary_operator + left: [ + (call target: (dot left: (_) right: (identifier) @function)) + (identifier) @function + ] operator: "/" right: (integer) @operator) + ]) + +(operator_identifier) @operator + +(unary_operator + operator: _ @operator) + +(binary_operator + operator: _ @operator) + +(dot + operator: _ @operator) + +(stab_clause + operator: _ @operator) + +; Literals + +(nil) @constant.builtin + +(boolean) @constant.builtin.boolean + +[ + (integer) + (float) +] @number + +(alias) @type + +(call + target: (dot + left: (atom) @type)) + +(char) @constant.character + +; Quoted content + +(interpolation "#{" @escape "}" @escape) @embedded (escape_sequence) @escape -(call function: (function_identifier) @keyword - (#match? @keyword "^(defmodule|defexception|defp|def|with|case|cond|raise|import|require|use|defmacrop|defmacro|defguardp|defguard|defdelegate|defstruct|alias|defimpl|defprotocol|defoverridable|receive|if|for|try|throw|unless|reraise|super|quote|unquote|unquote_splicing)$")) +[ + (atom) + (quoted_atom) + (keyword) + (quoted_keyword) +] @string.special.symbol -(call function: (function_identifier) @keyword - [(call - function: (function_identifier) @function - (arguments - [(identifier) @variable.parameter - (_ (identifier) @variable.parameter) - (_ (_ (identifier) @variable.parameter)) - (_ (_ (_ (identifier) @variable.parameter))) - (_ (_ (_ (_ (identifier) @variable.parameter)))) - (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))])) - (binary_op - left: - (call - function: (function_identifier) @function - (arguments - [(identifier) @variable.parameter - (_ (identifier) @variable.parameter) - (_ (_ (identifier) @variable.parameter)) - (_ (_ (_ (identifier) @variable.parameter))) - (_ (_ (_ (_ (identifier) @variable.parameter)))) - (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))])) +[ + (string) + (charlist) +] @string + +; Note that we explicitly target sigil quoted start/end, so they are not overridden by delimiters + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string + quoted_end: _ @string + (#match? @__name__ "^[sS]$")) @string + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string.regex + quoted_end: _ @string.regex + (#match? @__name__ "^[rR]$")) @string.regex + +(sigil + (sigil_name) @__name__ + quoted_start: _ @string.special + quoted_end: _ @string.special) @string.special + +; Calls + +; * definition keyword +(call + target: (identifier) @keyword + (#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$")) + +; * kernel or special forms keyword +(call + target: (identifier) @keyword + (#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$")) + +; * function call +(call + target: [ + ; local + (identifier) @function + ; remote + (dot + right: (identifier) @function) + ]) + +; * just identifier in function definition +(call + target: (identifier) @keyword + (arguments + [ + (identifier) @function + (binary_operator + left: (identifier) @function operator: "when") - (binary_op - left: (identifier) @variable.parameter - operator: _ @function - right: (identifier) @variable.parameter)] - (#match? @keyword "^(defp|def|defmacrop|defmacro|defguardp|defguard|defdelegate)$")) + ]) + (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) -(call (function_identifier) @keyword - [(call - function: (function_identifier) @function) - (identifier) @function - (binary_op - left: - [(call - function: (function_identifier) @function) - (identifier) @function] - operator: "when")] - (#match? @keyword "^(defp|def|defmacrop|defmacro|defguardp|defguard|defdelegate)$")) +; * pipe into identifier (definition) +(call + target: (identifier) @keyword + (arguments + (binary_operator + operator: "|>" + right: (identifier) @variable)) + (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) -(anonymous_function - (stab_expression - left: (bare_arguments - [(identifier) @variable.parameter - (_ (identifier) @variable.parameter) - (_ (_ (identifier) @variable.parameter)) - (_ (_ (_ (identifier) @variable.parameter))) - (_ (_ (_ (_ (identifier) @variable.parameter)))) - (_ (_ (_ (_ (_ (identifier) @variable.parameter)))))]))) +; * pipe into identifier (function call) +(binary_operator + operator: "|>" + right: (identifier) @function) -(unary_op - operator: "@" - (call (identifier) @attribute - (heredoc - [(heredoc_start) - (heredoc_content) - (heredoc_end)] @doc)) - (#match? @attribute "^(doc|moduledoc)$")) +; Identifiers -(module) @type +; * special +( + (identifier) @constant.builtin + (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$") +) -(unary_op - operator: "@" @attribute - [(call - function: (function_identifier) @attribute) - (identifier) @attribute]) +; * unused +( + (identifier) @comment + (#match? @comment "^_") +) -(unary_op - operator: _ @operator) +; * regular +(identifier) @variable -(binary_op - operator: _ @operator) +; Comment -(heredoc - [(heredoc_start) - (heredoc_content) - (heredoc_end)] @string) +(comment) @comment -(string - [(string_start) - (string_content) - (string_end)] @string) +; Punctuation -(sigil_start) @string.special -(sigil_content) @string -(sigil_end) @string.special - -(interpolation - "#{" @punctuation.special - "}" @punctuation.special) +[ + "%" +] @punctuation [ "," - "->" - "." + ";" ] @punctuation.delimiter [ @@ -133,6 +221,4 @@ ">>" ] @punctuation.bracket -(special_identifier) @function.special - (ERROR) @warning