summaryrefslogtreecommitdiff
path: root/lisp/progmodes/elixir-ts-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/elixir-ts-mode.el')
-rw-r--r--lisp/progmodes/elixir-ts-mode.el66
1 files changed, 53 insertions, 13 deletions
diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el
index 286f3e39f43..c58854c41c3 100644
--- a/lisp/progmodes/elixir-ts-mode.el
+++ b/lisp/progmodes/elixir-ts-mode.el
@@ -55,7 +55,9 @@
(declare-function treesit-parser-list "treesit.c")
(declare-function treesit-node-parent "treesit.c")
(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-end "treesit.c")
(declare-function treesit-query-compile "treesit.c")
+(declare-function treesit-query-capture "treesit.c")
(declare-function treesit-node-eq "treesit.c")
(declare-function treesit-node-prev-sibling "treesit.c")
@@ -169,7 +171,13 @@
(defun elixir-ts--argument-indent-offset (node _parent &rest _)
"Return the argument offset position for NODE."
- (if (treesit-node-prev-sibling node t) 0 elixir-ts-indent-offset))
+ (if (or (treesit-node-prev-sibling node t)
+ ;; Don't indent if this is the first node or
+ ;; if the line is empty.
+ (save-excursion
+ (beginning-of-line)
+ (looking-at-p "[[:blank:]]*$")))
+ 0 elixir-ts-indent-offset))
(defun elixir-ts--argument-indent-anchor (node parent &rest _)
"Return the argument anchor position for NODE and PARENT."
@@ -264,7 +272,7 @@
;; Handle incomplete maps when parent is ERROR.
((n-p-gp "^binary_operator$" "ERROR" nil) parent-bol 0)
;; When there is an ERROR, just indent to prev-line.
- ((parent-is "ERROR") prev-line 0)
+ ((parent-is "ERROR") prev-line ,offset)
((node-is "^binary_operator$")
(lambda (node parent &rest _)
(let ((top-level
@@ -449,16 +457,13 @@
:override t
`((sigil
(sigil_name) @elixir-ts-font-sigil-name-face
- quoted_start: _ @font-lock-string-face
- quoted_end: _ @font-lock-string-face
- (:match "^[sSwWpP]$" @elixir-ts-font-sigil-name-face))
+ (:match "^[sSwWpPUD]$" @elixir-ts-font-sigil-name-face))
@font-lock-string-face
(sigil
+ "~" @font-lock-string-face
(sigil_name) @elixir-ts-font-sigil-name-face
- quoted_start: _ @font-lock-regex-face
- quoted_end: _ @font-lock-regex-face
(:match "^[rR]$" @elixir-ts-font-sigil-name-face))
- @font-lock-regex-face
+ @font-lock-regexp-face
(sigil
"~" @font-lock-string-face
(sigil_name) @elixir-ts-font-sigil-name-face
@@ -547,13 +552,43 @@ Return nil if NODE is not a defun node or doesn't have a name."
(_ nil))))
(_ nil)))
+(defvar elixir-ts--syntax-propertize-query
+ (when (treesit-available-p)
+ (treesit-query-compile
+ 'elixir
+ '(((["\"\"\""] @quoted-text))))))
+
+(defun elixir-ts--syntax-propertize (start end)
+ "Apply syntax text properties between START and END for `elixir-ts-mode'."
+ (let ((captures
+ (treesit-query-capture 'elixir elixir-ts--syntax-propertize-query start end)))
+ (pcase-dolist (`(,name . ,node) captures)
+ (pcase-exhaustive name
+ ('quoted-text
+ (put-text-property (1- (treesit-node-end node)) (treesit-node-end node)
+ 'syntax-table (string-to-syntax "$")))))))
+
+(defun elixir-ts--electric-pair-string-delimiter ()
+ "Insert corresponding multi-line string for `electric-pair-mode'."
+ (when (and electric-pair-mode
+ (eq last-command-event ?\")
+ (let ((count 0))
+ (while (eq (char-before (- (point) count)) last-command-event)
+ (cl-incf count))
+ (= count 3))
+ (eq (char-after) last-command-event))
+ (save-excursion
+ (insert (make-string 2 last-command-event)))
+ (save-excursion
+ (newline 1 t))))
+
;;;###autoload
(define-derived-mode elixir-ts-mode prog-mode "Elixir"
"Major mode for editing Elixir, powered by tree-sitter."
:group 'elixir-ts
:syntax-table elixir-ts--syntax-table
- ;; Comments
+ ;; Comments.
(setq-local comment-start "# ")
(setq-local comment-start-skip
(rx "#" (* (syntax whitespace))))
@@ -563,9 +598,13 @@ Return nil if NODE is not a defun node or doesn't have a name."
(rx (* (syntax whitespace))
(group (or (syntax comment-end) "\n"))))
- ;; Compile
+ ;; Compile.
(setq-local compile-command "mix")
+ ;; Electric pair.
+ (add-hook 'post-self-insert-hook
+ #'elixir-ts--electric-pair-string-delimiter 'append t)
+
(when (treesit-ready-p 'elixir)
;; The HEEx parser has to be created first for elixir to ensure elixir
;; is the first language when looking for treesit ranges.
@@ -596,14 +635,14 @@ Return nil if NODE is not a defun node or doesn't have a name."
;; Indent.
(setq-local treesit-simple-indent-rules elixir-ts--indent-rules)
- ;; Navigation
+ ;; Navigation.
(setq-local forward-sexp-function #'elixir-ts--forward-sexp)
(setq-local treesit-defun-type-regexp
'("call" . elixir-ts--defun-p))
(setq-local treesit-defun-name-function #'elixir-ts--defun-name)
- ;; Embedded Heex
+ ;; Embedded Heex.
(when (treesit-ready-p 'heex)
(setq-local treesit-range-settings elixir-ts--treesit-range-rules)
@@ -627,7 +666,8 @@ Return nil if NODE is not a defun node or doesn't have a name."
( elixir-sigil elixir-string-escape
elixir-string-interpolation ))))
- (treesit-major-mode-setup)))
+ (treesit-major-mode-setup)
+ (setq-local syntax-propertize-function #'elixir-ts--syntax-propertize)))
(if (treesit-ready-p 'elixir)
(progn