:group 'elixir-ts
:version "30.1")
-(defface elixir-ts-font-comment-doc-identifier-face
+(defface elixir-ts-comment-doc-identifier
'((t (:inherit font-lock-doc-face)))
- "Face used for @comment.doc tags in Elixir files.")
+ "Face used for doc identifiers in Elixir files."
+ :group 'elixir-ts)
-(defface elixir-ts-font-comment-doc-attribute-face
+(defface elixir-ts-comment-doc-attribute
'((t (:inherit font-lock-doc-face)))
- "Face used for @comment.doc.__attribute__ tags in Elixir files.")
+ "Face used for doc attributes in Elixir files."
+ :group 'elixir-ts)
-(defface elixir-ts-font-sigil-name-face
+(defface elixir-ts-sigil-name
'((t (:inherit font-lock-string-face)))
- "Face used for @__name__ tags in Elixir files.")
+ "Face used for sigils in Elixir files."
+ :group 'elixir-ts)
+
+(defface elixir-ts-atom
+ '((t (:inherit font-lock-constant-face)))
+ "Face used for atoms in Elixir files."
+ :group 'elixir-ts)
+
+(defface elixir-ts-keyword-key
+ '((t (:inherit elixir-ts-atom)))
+ "Face used for keyword keys in Elixir files."
+ :group 'elixir-ts)
+
+(defface elixir-ts-attribute
+ '((t (:inherit font-lock-preprocessor-face)))
+ "Face used for attributes in Elixir files."
+ :group 'elixir-ts)
(defconst elixir-ts--sexp-regexp
(rx bol
"defoverridable" "defp" "defprotocol" "defstruct"))
(defconst elixir-ts--definition-keywords-re
- (concat "^" (regexp-opt elixir-ts--definition-keywords) "$"))
+ (concat "^" (regexp-opt
+ (append elixir-ts--definition-keywords
+ elixir-ts--test-definition-keywords))
+ "$"))
(defconst elixir-ts--kernel-keywords
'("alias" "case" "cond" "else" "for" "if" "import" "quote"
(treesit-node-start
(treesit-node-parent
(treesit-node-at (point) 'elixir))))
- 0)))))
+ 0)))))
(defvar elixir-ts--font-lock-settings
(treesit-font-lock-rules
:language 'elixir
- :feature 'elixir-comment
- '((comment) @font-lock-comment-face)
-
- :language 'elixir
- :feature 'elixir-string
- :override t
- '([(string) (charlist)] @font-lock-string-face)
-
+ :feature 'elixir-function-name
+ `((call target: (identifier) @target-identifier
+ (arguments (identifier) @font-lock-function-name-face)
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (call target: (identifier) @target-identifier
+ (arguments
+ (call target: (identifier) @font-lock-function-name-face))
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (call target: (identifier) @target-identifier
+ (arguments
+ (binary_operator
+ left: (call target: (identifier) @font-lock-function-name-face)))
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (call target: (identifier) @target-identifier
+ (arguments (identifier) @font-lock-function-name-face)
+ (do_block)
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (call target: (identifier) @target-identifier
+ (arguments
+ (call target: (identifier) @font-lock-function-name-face))
+ (do_block)
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (call target: (identifier) @target-identifier
+ (arguments
+ (binary_operator
+ left: (call target: (identifier) @font-lock-function-name-face)))
+ (do_block)
+ (:match ,elixir-ts--definition-keywords-re @target-identifier))
+ (unary_operator
+ operator: "@"
+ (call (arguments
+ (binary_operator
+ left: (call target: (identifier) @font-lock-function-name-face))))))
+
+ ;; A function definition like "def _foo" is valid, but we should
+ ;; not apply the comment-face unless its a non-function identifier, so
+ ;; the comment matches has to be after the function matches.
:language 'elixir
- :feature 'elixir-string-interpolation
- :override t
- '((string
- [
- quoted_end: _ @font-lock-string-face
- quoted_start: _ @font-lock-string-face
- (quoted_content) @font-lock-string-face
- (interpolation
- "#{" @font-lock-regexp-grouping-backslash "}"
- @font-lock-regexp-grouping-backslash)
- ])
- (charlist
- [
- quoted_end: _ @font-lock-string-face
- quoted_start: _ @font-lock-string-face
- (quoted_content) @font-lock-string-face
- (interpolation
- "#{" @font-lock-regexp-grouping-backslash "}"
- @font-lock-regexp-grouping-backslash)
- ]))
+ :feature 'elixir-comment
+ '((comment) @font-lock-comment-face
+ ((identifier) @font-lock-comment-face
+ (:match "^_[a-z]\\|^_$" @font-lock-comment-face)))
:language 'elixir
- :feature 'elixir-keyword
- `(,elixir-ts--reserved-keywords-vector
- @font-lock-keyword-face
- (binary_operator
- operator: _ @font-lock-keyword-face
- (:match ,elixir-ts--reserved-keywords-re @font-lock-keyword-face)))
+ :feature 'elixir-variable
+ `((call target: (identifier)
+ (arguments
+ (binary_operator
+ (call target: (identifier)
+ (arguments ((identifier) @font-lock-variable-use-face))))))
+ (call target: (identifier)
+ (arguments
+ (call target: (identifier)
+ (arguments ((identifier)) @font-lock-variable-use-face))))
+ (dot left: (identifier) @font-lock-variable-use-face operator: "." ))
:language 'elixir
:feature 'elixir-doc
- :override t
`((unary_operator
- operator: "@" @elixir-ts-font-comment-doc-attribute-face
+ operator: "@" @elixir-ts-comment-doc-attribute
operand: (call
- target: (identifier) @elixir-ts-font-comment-doc-identifier-face
+ target: (identifier) @elixir-ts-comment-doc-identifier
;; Arguments can be optional, so adding another
;; entry without arguments.
;; If we don't handle then we don't apply font
(charlist) @font-lock-doc-face
(sigil) @font-lock-doc-face
(boolean) @font-lock-doc-face
+ (keywords) @font-lock-doc-face
]))
(:match ,elixir-ts--doc-keywords-re
- @elixir-ts-font-comment-doc-identifier-face))
+ @elixir-ts-comment-doc-identifier))
(unary_operator
- operator: "@" @elixir-ts-font-comment-doc-attribute-face
+ operator: "@" @elixir-ts-comment-doc-attribute
operand: (call
- target: (identifier) @elixir-ts-font-comment-doc-identifier-face)
+ target: (identifier) @elixir-ts-comment-doc-identifier)
(:match ,elixir-ts--doc-keywords-re
- @elixir-ts-font-comment-doc-identifier-face)))
+ @elixir-ts-comment-doc-identifier)))
:language 'elixir
- :feature 'elixir-unary-operator
- `((unary_operator operator: "@" @font-lock-preprocessor-face
- operand: [
- (identifier) @font-lock-preprocessor-face
- (call target: (identifier)
- @font-lock-preprocessor-face)
- (boolean) @font-lock-preprocessor-face
- (nil) @font-lock-preprocessor-face
- ])
+ :feature 'elixir-string
+ '((interpolation
+ "#{" @font-lock-escape-face
+ "}" @font-lock-escape-face)
+ (string (quoted_content) @font-lock-string-face)
+ (quoted_keyword (quoted_content) @font-lock-string-face)
+ (charlist (quoted_content) @font-lock-string-face)
+ ["\"" "'" "\"\"\""] @font-lock-string-face)
- (unary_operator operator: "&") @font-lock-function-name-face
- (operator_identifier) @font-lock-operator-face)
+ :language 'elixir
+ :feature 'elixir-sigil
+ `((sigil
+ (sigil_name) @elixir-ts-sigil-name
+ (quoted_content) @font-lock-string-face
+ ;; HEEx and Surface templates will handled by
+ ;; heex-ts-mode if its available.
+ (:match "^[^HF]$" @elixir-ts-sigil-name))
+ @font-lock-string-face
+ (sigil
+ (sigil_name) @font-lock-regexp-face
+ (:match "^[rR]$" @font-lock-regexp-face))
+ @font-lock-regexp-face
+ (sigil
+ "~" @font-lock-string-face
+ (sigil_name) @font-lock-string-face
+ quoted_start: _ @font-lock-string-face
+ quoted_end: _ @font-lock-string-face))
:language 'elixir
:feature 'elixir-operator
- '((binary_operator operator: _ @font-lock-operator-face)
- (dot operator: _ @font-lock-operator-face)
- (stab_clause operator: _ @font-lock-operator-face)
-
- [(boolean) (nil)] @font-lock-constant-face
- [(integer) (float)] @font-lock-number-face
- (alias) @font-lock-type-face
- (call target: (dot left: (atom) @font-lock-type-face))
- (char) @font-lock-constant-face
- [(atom) (quoted_atom)] @font-lock-type-face
- [(keyword) (quoted_keyword)] @font-lock-builtin-face)
+ `(["!"] @font-lock-negation-char-face
+ ["%"] @font-lock-bracket-face
+ ["," ";"] @font-lock-operator-face
+ ["(" ")" "[" "]" "{" "}" "<<" ">>"] @font-lock-bracket-face)
:language 'elixir
- :feature 'elixir-call
- `((call
- target: (identifier) @font-lock-keyword-face
- (:match ,elixir-ts--definition-keywords-re @font-lock-keyword-face))
- (call
- target: (identifier) @font-lock-keyword-face
- (:match ,elixir-ts--kernel-keywords-re @font-lock-keyword-face))
- (call
- target: [(identifier) @font-lock-function-name-face
- (dot right: (identifier) @font-lock-keyword-face)])
+ :feature 'elixir-data-type
+ '([(atom) (alias)] @font-lock-type-face
+ (keywords (pair key: (keyword) @elixir-ts-keyword-key))
+ [(keyword) (quoted_keyword)] @elixir-ts-atom
+ [(boolean) (nil)] @elixir-ts-atom
+ (unary_operator operator: "@" @elixir-ts-attribute
+ operand: [
+ (identifier) @elixir-ts-attribute
+ (call target: (identifier)
+ @elixir-ts-attribute)
+ (boolean) @elixir-ts-attribute
+ (nil) @elixir-ts-attribute
+ ])
+ (operator_identifier) @font-lock-operator-face)
+
+ :language 'elixir
+ :feature 'elixir-keyword
+ `(,elixir-ts--reserved-keywords-vector
+ @font-lock-keyword-face
+ (binary_operator
+ operator: _ @font-lock-keyword-face
+ (:match ,elixir-ts--reserved-keywords-re @font-lock-keyword-face))
+ (binary_operator operator: _ @font-lock-operator-face)
(call
target: (identifier) @font-lock-keyword-face
- (arguments
- [
- (identifier) @font-lock-keyword-face
- (binary_operator
- left: (identifier) @font-lock-keyword-face
- operator: "when")
- ])
(:match ,elixir-ts--definition-keywords-re @font-lock-keyword-face))
(call
target: (identifier) @font-lock-keyword-face
- (arguments
- (binary_operator
- operator: "|>"
- right: (identifier)))
- (:match ,elixir-ts--definition-keywords-re @font-lock-keyword-face)))
+ (:match ,elixir-ts--kernel-keywords-re @font-lock-keyword-face)))
:language 'elixir
- :feature 'elixir-constant
- `((binary_operator operator: "|>" right: (identifier)
- @font-lock-function-name-face)
- ((identifier) @font-lock-keyword-face
- (:match ,elixir-ts--builtin-keywords-re
- @font-lock-keyword-face))
- ((identifier) @font-lock-comment-face
- (:match "^_" @font-lock-comment-face))
- (identifier) @font-lock-function-name-face
- ["%"] @font-lock-keyward-face
- ["," ";"] @font-lock-keyword-face
- ["(" ")" "[" "]" "{" "}" "<<" ">>"] @font-lock-keyword-face)
+ :feature 'elixir-function-call
+ '((call target: (identifier) @font-lock-function-call-face)
+ (unary_operator operator: "&" @font-lock-operator-face
+ operand: (binary_operator
+ left: (identifier)
+ @font-lock-function-call-face
+ operator: "/" right: (integer)))
+ (call
+ target: (dot right: (identifier) @font-lock-function-call-face))
+ (unary_operator operator: "&" @font-lock-variable-name-face
+ operand: (integer) @font-lock-variable-name-face)
+ (unary_operator operator: "&" @font-lock-operator-face
+ operand: (list)))
:language 'elixir
- :feature 'elixir-sigil
+ :feature 'elixir-string-escape
:override t
- `((sigil
- (sigil_name) @elixir-ts-font-sigil-name-face
- (:match "^[^HF]$" @elixir-ts-font-sigil-name-face))
- @font-lock-string-face
- (sigil
- (sigil_name) @font-lock-regexp-face
- (:match "^[rR]$" @font-lock-regexp-face))
- @font-lock-regexp-face
- (sigil
- "~" @font-lock-string-face
- (sigil_name) @elixir-ts-font-sigil-name-face
- quoted_start: _ @font-lock-string-face
- quoted_end: _ @font-lock-string-face
- (:match "^[HF]$" @elixir-ts-font-sigil-name-face)))
+ `((escape_sequence) @font-lock-escape-face)
:language 'elixir
- :feature 'elixir-string-escape
+ :feature 'elixir-number
+ '([(integer) (float)] @font-lock-number-face)
+
+ :language 'elixir
+ :feature 'elixir-variable
+ '((binary_operator left: (identifier) @font-lock-variable-name-face)
+ (binary_operator right: (identifier) @font-lock-variable-name-face)
+ (arguments ( (identifier) @font-lock-variable-name-face))
+ (tuple (identifier) @font-lock-variable-name-face)
+ (list (identifier) @font-lock-variable-name-face)
+ (pair value: (identifier) @font-lock-variable-name-face)
+ (body (identifier) @font-lock-variable-name-face)
+ (unary_operator operand: (identifier) @font-lock-variable-name-face)
+ (interpolation (identifier) @font-lock-variable-name-face)
+ (do_block (identifier) @font-lock-variable-name-face))
+
+ :language 'elixir
+ :feature 'elixir-builtin
:override t
- `((escape_sequence) @font-lock-regexp-grouping-backslash))
+ `(((identifier) @font-lock-builtin-face
+ (:match ,elixir-ts--builtin-keywords-re
+ @font-lock-builtin-face))))
+
"Tree-sitter font-lock settings.")
(defvar elixir-ts--treesit-range-rules
;; Font-lock.
(setq-local treesit-font-lock-settings elixir-ts--font-lock-settings)
(setq-local treesit-font-lock-feature-list
- '(( elixir-comment elixir-constant elixir-doc )
- ( elixir-string elixir-keyword elixir-unary-operator
- elixir-call elixir-operator )
- ( elixir-sigil elixir-string-escape elixir-string-interpolation)))
+ '(( elixir-comment elixir-doc elixir-function-name)
+ ( elixir-string elixir-keyword elixir-data-type)
+ ( elixir-sigil elixir-variable elixir-builtin
+ elixir-string-escape)
+ ( elixir-function-call elixir-operator elixir-number )))
+
;; Imenu.
(setq-local treesit-simple-imenu-settings
heex-ts--indent-rules))
(setq-local treesit-font-lock-feature-list
- '(( elixir-comment elixir-constant elixir-doc
+ '(( elixir-comment elixir-doc elixir-function-name
heex-comment heex-keyword heex-doctype )
- ( elixir-string elixir-keyword elixir-unary-operator
- elixir-call elixir-operator
- heex-component heex-tag heex-attribute heex-string)
- ( elixir-sigil elixir-string-escape
- elixir-string-interpolation ))))
+ ( elixir-string elixir-keyword elixir-data-type
+ heex-component heex-tag heex-attribute heex-string )
+ ( elixir-sigil elixir-variable elixir-builtin
+ elixir-string-escape)
+ ( elixir-function-call elixir-operator elixir-number ))))
(treesit-major-mode-setup)
(setq-local syntax-propertize-function #'elixir-ts--syntax-propertize)))