aboutsummaryrefslogtreecommitdiff
path: root/misc/emacs
diff options
context:
space:
mode:
Diffstat (limited to 'misc/emacs')
-rw-r--r--misc/emacs/nix-mode.el86
1 files changed, 84 insertions, 2 deletions
diff --git a/misc/emacs/nix-mode.el b/misc/emacs/nix-mode.el
index 10035e96e..e129e9efe 100644
--- a/misc/emacs/nix-mode.el
+++ b/misc/emacs/nix-mode.el
@@ -8,6 +8,20 @@
;;; Code:
+(defun nix-syntax-match-antiquote (limit)
+ (let ((pos (next-single-char-property-change (point) 'nix-syntax-antiquote
+ nil limit)))
+ (when (and pos (> pos (point)))
+ (goto-char pos)
+ (let ((char (char-after pos)))
+ (pcase char
+ (`?$
+ (forward-char 2))
+ (`?}
+ (forward-char 1)))
+ (set-match-data (list pos (point)))
+ t))))
+
(defconst nix-font-lock-keywords
'("\\_<if\\_>" "\\_<then\\_>" "\\_<else\\_>" "\\_<assert\\_>" "\\_<with\\_>"
"\\_<let\\_>" "\\_<in\\_>" "\\_<rec\\_>" "\\_<inherit\\_>" "\\_<or\\_>"
@@ -26,7 +40,8 @@
("<[a-zA-Z0-9._\\+-]+\\(/[a-zA-Z0-9._\\+-]+\\)*>"
. font-lock-constant-face)
("[a-zA-Z0-9._\\+-]*\\(/[a-zA-Z0-9._\\+-]+\\)+"
- . font-lock-constant-face))
+ . font-lock-constant-face)
+ (nix-syntax-match-antiquote 0 font-lock-preprocessor-face t))
"Font lock keywords for nix.")
(defvar nix-mode-syntax-table
@@ -38,6 +53,67 @@
table)
"Syntax table for Nix mode.")
+(defun nix-syntax-propertize-escaped-antiquote ()
+ "Set syntax properies for escaped antiquote marks."
+ nil)
+
+(defun nix-syntax-propertize-multiline-string ()
+ "Set syntax properies for multiline string delimiters."
+ (let* ((start (match-beginning 0))
+ (end (match-end 0))
+ (context (save-excursion (save-match-data (syntax-ppss start))))
+ (string-type (nth 3 context)))
+ (pcase string-type
+ (`t
+ ;; inside a multiline string
+ ;; ending multi-line string delimiter
+ (put-text-property (1- end) end
+ 'syntax-table (string-to-syntax "|")))
+ (`nil
+ ;; beginning multi-line string delimiter
+ (put-text-property start (1+ start)
+ 'syntax-table (string-to-syntax "|"))))))
+
+(defun nix-syntax-propertize-antiquote ()
+ "Set syntax properties for antiquote marks."
+ (let* ((start (match-beginning 0)))
+ (put-text-property start (1+ start)
+ 'syntax-table (string-to-syntax "|"))
+ (put-text-property start (+ start 2)
+ 'nix-syntax-antiquote t)))
+
+(defun nix-syntax-propertize-close-brace ()
+ "Set syntax properties for close braces.
+If a close brace `}' ends an antiquote, the next character begins a string."
+ (let* ((start (match-beginning 0))
+ (end (match-end 0))
+ (context (save-excursion (save-match-data (syntax-ppss start))))
+ (open (nth 1 context)))
+ (when open ;; a corresponding open-brace was found
+ (let* ((antiquote (get-text-property open 'nix-syntax-antiquote)))
+ (when antiquote
+ (put-text-property (+ start 1) (+ start 2)
+ 'syntax-table (string-to-syntax "|"))
+ (put-text-property start (1+ start)
+ 'nix-syntax-antiquote t))))))
+
+(defun nix-syntax-propertize (start end)
+ "Special syntax properties for Nix."
+ ;; search for multi-line string delimiters
+ (goto-char start)
+ (remove-text-properties start end '(syntax-table nil nix-syntax-antiquote nil))
+ (funcall
+ (syntax-propertize-rules
+ ("''\\${"
+ (0 (ignore (nix-syntax-propertize-escaped-antiquote))))
+ ("''"
+ (0 (ignore (nix-syntax-propertize-multiline-string))))
+ ("\\${"
+ (0 (ignore (nix-syntax-propertize-antiquote))))
+ ("}"
+ (0 (ignore (nix-syntax-propertize-close-brace)))))
+ start end))
+
(defun nix-indent-line ()
"Indent current line in a Nix expression."
(interactive)
@@ -69,7 +145,13 @@ The hook `nix-mode-hook' is run when Nix mode is started.
(set-syntax-table nix-mode-syntax-table)
;; Font lock support.
- (setq font-lock-defaults '(nix-font-lock-keywords nil nil nil nil))
+ (setq-local font-lock-defaults '(nix-font-lock-keywords nil nil nil nil))
+
+ ;; Special syntax properties for Nix
+ (setq-local syntax-propertize-function 'nix-syntax-propertize)
+
+ ;; Look at text properties when parsing
+ (setq-local parse-sexp-lookup-properties t)
;; Automatic indentation [C-j].
(set (make-local-variable 'indent-line-function) 'nix-indent-line)