Skip to content

Commit 66438d4

Browse files
committed
Merge pull request #2 from MicahChalmer/fix-quotes-with-syntax-properties
Fix quotes with syntax properties
2 parents 149cfdd + e6e16cc commit 66438d4

File tree

2 files changed

+73
-14
lines changed

2 files changed

+73
-14
lines changed

rust-mode-tests.el

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,18 @@ fn foo() {
526526
"
527527
))
528528

529+
;; Closing braces in single char literals and strings should not confuse the indentation
530+
(ert-deftest indent-closing-braces-in-char-literals ()
531+
(test-indent
532+
"
533+
fn foo() {
534+
{ bar('}'); }
535+
{ bar(']'); }
536+
{ bar(')'); }
537+
}
538+
"
539+
))
540+
529541
(setq rust-test-motion-string
530542
"
531543
fn fn1(arg: int) -> bool {
@@ -893,3 +905,17 @@ list of substrings of `STR' each followed by its face."
893905
"/* #[foo] */"
894906
'("/* " font-lock-comment-delimiter-face
895907
"#[foo] */" font-lock-comment-face)))
908+
909+
(ert-deftest font-lock-double-quote-character-literal ()
910+
(rust-test-font-lock
911+
"'\"'; let"
912+
'("'\"'" font-lock-string-face
913+
"let" font-lock-keyword-face)))
914+
915+
(ert-deftest font-lock-single-quote-character-literal ()
916+
(rust-test-font-lock
917+
"fn main() { let ch = '\\''; }"
918+
'("fn" font-lock-keyword-face
919+
"main" font-lock-function-name-face
920+
"let" font-lock-keyword-face
921+
"'\\''" font-lock-string-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)