summaryrefslogtreecommitdiff
path: root/rust-mode.el
diff options
context:
space:
mode:
authorAankhen <Aankhen@users.noreply.github.com>2017-07-29 00:49:29 +0530
committerAankhen <Aankhen@users.noreply.github.com>2017-08-02 12:34:01 +0530
commit89320ad26b8768e5db40e97c35be9f2b690ab9c5 (patch)
tree1855566c379b9faf027063709dbbe5cb9aae4d6a /rust-mode.el
parent09efc45dee786cb220c233426ddd82b26ad950eb (diff)
downloadrust-mode-89320ad26b8768e5db40e97c35be9f2b690ab9c5.tar.gz
Highlight interpolation in arguments to print! &c.
Diffstat (limited to 'rust-mode.el')
-rw-r--r--rust-mode.el82
1 files changed, 82 insertions, 0 deletions
diff --git a/rust-mode.el b/rust-mode.el
index eac246f..8ae2454 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -170,7 +170,18 @@ function or trait. When nil, where will be aligned with fn or trait."
"Face for the question mark operator."
:group 'rust-mode)
+(defface rust-builtin-formatting-macro-face
+ '((t :inherit font-lock-builtin-face))
+ "Face for builtin formatting macros (print! &c.)."
+ :group 'rust-mode)
+
+(defface rust-string-interpolation-face
+ '((t :slant italic :inherit font-lock-string-face))
+ "Face for interpolating braces in builtin formatting macro strings."
+ :group 'rust-mode)
+
(defun rust-paren-level () (nth 0 (syntax-ppss)))
+(defun rust-in-str () (nth 3 (syntax-ppss)))
(defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss)))
(defun rust-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss))))
@@ -573,6 +584,54 @@ the desired identifiers), but does not match type annotations \"foo::<\"."
((not (looking-at (rx (0+ space) "<")))
(throw 'rust-path-font-lock-matcher match))))))))
+(defun rust-next-string-interpolation (limit)
+ "Search forward from point for next Rust interpolation marker
+before LIMIT.
+Set point to the end of the occurrence found, and return match beginning
+and end."
+ (catch 'match
+ (save-match-data
+ (save-excursion
+ (while (search-forward "{" limit t)
+ (if (eql (char-after (point)) ?{)
+ (forward-char)
+ (let ((start (match-beginning 0)))
+ ;; According to fmt_macros::Parser::next, an opening brace
+ ;; must be followed by an optional argument and/or format
+ ;; specifier, then a closing brace. A single closing brace
+ ;; without a corresponding unescaped opening brace is an
+ ;; error. We don't need to do anything special with
+ ;; arguments, specifiers, or errors, so we only search for
+ ;; the single closing brace.
+ (when (search-forward "}" limit t)
+ (throw 'match (list start (point)))))))))))
+
+(defun rust-string-interpolation-matcher (limit)
+ "Match next Rust interpolation marker before LIMIT and set
+match data if found. Returns nil if not within a Rust string."
+ (when (rust-in-str)
+ (let ((match (rust-next-string-interpolation limit)))
+ (when match
+ (set-match-data match)
+ (goto-char (cadr match))
+ match))))
+
+(defvar rust-builtin-formatting-macros
+ '("eprint"
+ "eprintln"
+ "format"
+ "print"
+ "println")
+ "List of builtin Rust macros for string formatting used by `rust-mode-font-lock-keywords'. (`write!' is handled separately.)")
+
+(defvar rust-formatting-macro-opening-re
+ "[[:space:]]*[({[][[:space:]]*"
+ "Regular expression to match the opening delimiter of a Rust formatting macro.")
+
+(defvar rust-start-of-string-re
+ "\\(?:r#*\\)?\""
+ "Regular expression to match the start of a Rust raw string.")
+
(defvar rust-mode-font-lock-keywords
(append
`(
@@ -590,6 +649,22 @@ the desired identifiers), but does not match type annotations \"foo::<\"."
(,(rust-re-grab (concat "#\\!?\\[" rust-re-ident "[^]]*\\]"))
1 font-lock-preprocessor-face keep)
+ ;; Builtin formatting macros
+ (,(concat (rust-re-grab (concat (regexp-opt rust-builtin-formatting-macros) "!")) (concat rust-formatting-macro-opening-re rust-start-of-string-re))
+ (1 'rust-builtin-formatting-macro-face)
+ (rust-string-interpolation-matcher
+ (rust-end-of-string)
+ nil
+ (0 'rust-string-interpolation-face t nil)))
+
+ ;; write! macro
+ (,(concat (rust-re-grab "write\\(ln\\)?!") (concat rust-formatting-macro-opening-re "[[:space:]]*[^\"]+,[[:space:]]*" rust-start-of-string-re))
+ (1 'rust-builtin-formatting-macro-face)
+ (rust-string-interpolation-matcher
+ (rust-end-of-string)
+ nil
+ (0 'rust-string-interpolation-face t nil)))
+
;; Syntax extension invocations like `foo!`, highlight including the !
(,(concat (rust-re-grab (concat rust-re-ident "!")) "[({[:space:][]")
1 font-lock-preprocessor-face)
@@ -1215,6 +1290,13 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
;; There is no opening brace, so consider the whole buffer to be one "defun"
(goto-char (point-max))))
+(defun rust-end-of-string ()
+ "Skip to the end of the current string."
+ (save-excursion
+ (skip-syntax-forward "^\"|")
+ (skip-syntax-forward "\"|")
+ (point)))
+
;; Formatting using rustfmt
(defun rust--format-call (buf)
"Format BUF using rustfmt."