From 55080f6744fc11b92016c3babcf4d35c2e4995a6 Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 01:59:20 -0500 Subject: 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. --- rust-mode-tests.el | 6 ++++++ rust-mode.el | 61 +++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/rust-mode-tests.el b/rust-mode-tests.el index 54b4524..0df9060 100644 --- a/rust-mode-tests.el +++ b/rust-mode-tests.el @@ -893,3 +893,9 @@ list of substrings of `STR' each followed by its face." "/* #[foo] */" '("/* " font-lock-comment-delimiter-face "#[foo] */" font-lock-comment-face))) + +(ert-deftest font-lock-double-quote-character-literal () + (rust-test-font-lock + "'\"'; let" + '("'\"'" font-lock-string-face + "let" font-lock-keyword-face))) diff --git a/rust-mode.el b/rust-mode.el index dae685f..70b49fe 100644 --- a/rust-mode.el +++ b/rust-mode.el @@ -44,6 +44,13 @@ table)) +(defvar rust-mode-character-literal-syntax-table + (let ((table (make-syntax-table rust-mode-syntax-table))) + (modify-syntax-entry ?' "\"" table) + (modify-syntax-entry ?\" "_" table) + + table)) + (defgroup rust-mode nil "Support for Rust code." :link '(url-link "http://www.rust-lang.org/") @@ -259,14 +266,6 @@ ;; Lifetimes like `'foo` (,(concat "'" (rust-re-grab rust-re-ident) "[^']") 1 font-lock-variable-name-face) - ;; Character constants, since they're not treated as strings - ;; in order to have sufficient leeway to parse 'lifetime above. - (,(rust-re-grab "'[^']'") 1 font-lock-string-face) - (,(rust-re-grab "'\\\\[nrt]'") 1 font-lock-string-face) - (,(rust-re-grab "'\\\\x[[:xdigit:]]\\{2\\}'") 1 font-lock-string-face) - (,(rust-re-grab "'\\\\u[[:xdigit:]]\\{4\\}'") 1 font-lock-string-face) - (,(rust-re-grab "'\\\\U[[:xdigit:]]\\{8\\}'") 1 font-lock-string-face) - ;; CamelCase Means Type Or Constructor (,(rust-re-grabword rust-re-CamelCase) 1 font-lock-type-face) ) @@ -439,12 +438,19 @@ Assume that this is called after beginning-of-defun. So point is at the beginning of the defun body. This is written mainly to be used as `end-of-defun-function' for Rust." - (interactive "p") + (interactive) ;; Find the opening brace - (re-search-forward "[{]" nil t) - (goto-char (match-beginning 0)) - ;; Go to the closing brace - (forward-sexp)) + (if (re-search-forward "[{]" nil t) + (progn + (goto-char (match-beginning 0)) + ;; Go to the closing brace + (condition-case err + (forward-sexp) + (scan-error + ;; The parentheses are unbalanced; instead of being unable to fontify, just jump to the end of the buffer + (goto-char (point-max))))) + ;; There is no opening brace, so consider the whole buffer to be one "defun" + (goto-char (point-max)))) ;; For compatibility with Emacs < 24, derive conditionally (defalias 'rust-parent-mode @@ -481,7 +487,34 @@ This is written mainly to be used as `end-of-defun-function' for Rust." (setq-local comment-line-break-function 'rust-comment-indent-new-line) (setq-local imenu-generic-expression rust-imenu-generic-expression) (setq-local beginning-of-defun-function 'rust-beginning-of-defun) - (setq-local end-of-defun-function 'rust-end-of-defun)) + (setq-local end-of-defun-function 'rust-end-of-defun) + (setq-local parse-sexp-lookup-properties t) + (add-hook 'syntax-propertize-extend-region-functions 'rust-syntax-propertize-extend-region) + (setq-local syntax-propertize-function 'rust-syntax-propertize)) + +(defun rust-syntax-propertize-extend-region (start end) + (save-excursion + (goto-char start) + (beginning-of-defun) + (cons + (point) + (progn + (goto-char end) + (end-of-defun) + (point))))) + +(defun rust-syntax-propertize (start end) + ;; Find character literals and make the syntax table recognize the single quote as the string delimiter + (dolist (char-lit-re + '("'[^']'" + "'\\\\['nrt]'" + "'\\\\x[[:xdigit:]]\\{2\\}'" + "'\\\\u[[:xdigit:]]\\{4\\}'" + "'\\\\U[[:xdigit:]]\\{8\\}'")) + (save-excursion + (goto-char start) + (while (re-search-forward char-lit-re end t) + (put-text-property (match-beginning 0) (match-end 0) 'syntax-table rust-mode-character-literal-syntax-table))))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode)) -- cgit v1.2.3 From 9c0846aa4580685b343921a7eefb0ccfd3f0633e Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 20:31:04 -0500 Subject: Add test for '\'' single quote char literal --- rust-mode-tests.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust-mode-tests.el b/rust-mode-tests.el index 0df9060..f4512f4 100644 --- a/rust-mode-tests.el +++ b/rust-mode-tests.el @@ -899,3 +899,11 @@ list of substrings of `STR' each followed by its face." "'\"'; let" '("'\"'" font-lock-string-face "let" font-lock-keyword-face))) + +(ert-deftest font-lock-single-quote-character-literal () + (rust-test-font-lock + "fn main() { let ch = '\\''; }" + '("fn" font-lock-keyword-face + "main" font-lock-function-name-face + "let" font-lock-keyword-face + "'\\''" font-lock-string-face))) -- cgit v1.2.3 From e6e16ccc21a64f4b333273f58a7bd6d0376f70f4 Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 20:37:16 -0500 Subject: Add test for closing braces in character literals --- rust-mode-tests.el | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rust-mode-tests.el b/rust-mode-tests.el index f4512f4..2b18728 100644 --- a/rust-mode-tests.el +++ b/rust-mode-tests.el @@ -526,6 +526,18 @@ fn foo() { " )) +;; Closing braces in single char literals and strings should not confuse the indentation +(ert-deftest indent-closing-braces-in-char-literals () + (test-indent + " +fn foo() { + { bar('}'); } + { bar(']'); } + { bar(')'); } +} +" + )) + (setq rust-test-motion-string " fn fn1(arg: int) -> bool { -- cgit v1.2.3