diff options
Diffstat (limited to 'lisp/progmodes/elixir-ts-mode.el')
-rw-r--r-- | lisp/progmodes/elixir-ts-mode.el | 66 |
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 |