Skip to content

Commit 55080f6

Browse files
committed
Fix syntax and highlighting for char literals
This uses syntax properties to make it so that emacs recognizes the single quote, rather than the double quote, as the string delimiter within character literals, while leaving the syntax unchanged elsewhere.
1 parent 67f4832 commit 55080f6

File tree

2 files changed

+53
-14
lines changed

2 files changed

+53
-14
lines changed

rust-mode-tests.el

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,3 +893,9 @@ list of substrings of `STR' each followed by its face."
893893
"/* #[foo] */"
894894
'("/* " font-lock-comment-delimiter-face
895895
"#[foo] */" font-lock-comment-face)))
896+
897+
(ert-deftest font-lock-double-quote-character-literal ()
898+
(rust-test-font-lock
899+
"'\"'; let"
900+
'("'\"'" font-lock-string-face
901+
"let" font-lock-keyword-face)))

rust-mode.el

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@
4444

4545
table))
4646

47+
(defvar rust-mode-character-literal-syntax-table
48+
(let ((table (make-syntax-table rust-mode-syntax-table)))
49+
(modify-syntax-entry ?' "\"" table)
50+
(modify-syntax-entry ?\" "_" table)
51+
52+
table))
53+
4754
(defgroup rust-mode nil
4855
"Support for Rust code."
4956
:link '(url-link "http://www.rust-lang.org/")
@@ -259,14 +266,6 @@
259266
;; Lifetimes like `'foo`
260267
(,(concat "'" (rust-re-grab rust-re-ident) "[^']") 1 font-lock-variable-name-face)
261268

262-
;; Character constants, since they're not treated as strings
263-
;; in order to have sufficient leeway to parse 'lifetime above.
264-
(,(rust-re-grab "'[^']'") 1 font-lock-string-face)
265-
(,(rust-re-grab "'\\\\[nrt]'") 1 font-lock-string-face)
266-
(,(rust-re-grab "'\\\\x[[:xdigit:]]\\{2\\}'") 1 font-lock-string-face)
267-
(,(rust-re-grab "'\\\\u[[:xdigit:]]\\{4\\}'") 1 font-lock-string-face)
268-
(,(rust-re-grab "'\\\\U[[:xdigit:]]\\{8\\}'") 1 font-lock-string-face)
269-
270269
;; CamelCase Means Type Or Constructor
271270
(,(rust-re-grabword rust-re-CamelCase) 1 font-lock-type-face)
272271
)
@@ -439,12 +438,19 @@ Assume that this is called after beginning-of-defun. So point is
439438
at the beginning of the defun body.
440439
441440
This is written mainly to be used as `end-of-defun-function' for Rust."
442-
(interactive "p")
441+
(interactive)
443442
;; Find the opening brace
444-
(re-search-forward "[{]" nil t)
445-
(goto-char (match-beginning 0))
446-
;; Go to the closing brace
447-
(forward-sexp))
443+
(if (re-search-forward "[{]" nil t)
444+
(progn
445+
(goto-char (match-beginning 0))
446+
;; Go to the closing brace
447+
(condition-case err
448+
(forward-sexp)
449+
(scan-error
450+
;; The parentheses are unbalanced; instead of being unable to fontify, just jump to the end of the buffer
451+
(goto-char (point-max)))))
452+
;; There is no opening brace, so consider the whole buffer to be one "defun"
453+
(goto-char (point-max))))
448454

449455
;; For compatibility with Emacs < 24, derive conditionally
450456
(defalias 'rust-parent-mode
@@ -481,7 +487,34 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
481487
(setq-local comment-line-break-function 'rust-comment-indent-new-line)
482488
(setq-local imenu-generic-expression rust-imenu-generic-expression)
483489
(setq-local beginning-of-defun-function 'rust-beginning-of-defun)
484-
(setq-local end-of-defun-function 'rust-end-of-defun))
490+
(setq-local end-of-defun-function 'rust-end-of-defun)
491+
(setq-local parse-sexp-lookup-properties t)
492+
(add-hook 'syntax-propertize-extend-region-functions 'rust-syntax-propertize-extend-region)
493+
(setq-local syntax-propertize-function 'rust-syntax-propertize))
494+
495+
(defun rust-syntax-propertize-extend-region (start end)
496+
(save-excursion
497+
(goto-char start)
498+
(beginning-of-defun)
499+
(cons
500+
(point)
501+
(progn
502+
(goto-char end)
503+
(end-of-defun)
504+
(point)))))
505+
506+
(defun rust-syntax-propertize (start end)
507+
;; Find character literals and make the syntax table recognize the single quote as the string delimiter
508+
(dolist (char-lit-re
509+
'("'[^']'"
510+
"'\\\\['nrt]'"
511+
"'\\\\x[[:xdigit:]]\\{2\\}'"
512+
"'\\\\u[[:xdigit:]]\\{4\\}'"
513+
"'\\\\U[[:xdigit:]]\\{8\\}'"))
514+
(save-excursion
515+
(goto-char start)
516+
(while (re-search-forward char-lit-re end t)
517+
(put-text-property (match-beginning 0) (match-end 0) 'syntax-table rust-mode-character-literal-syntax-table)))))
485518

486519
;;;###autoload
487520
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode))

0 commit comments

Comments
 (0)