From 67f483238447d465eaaf1d82b9d85fa8d7fc2bec Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 00:01:02 -0500 Subject: [PATCH 1/4] Fix tests broken by trailing whitespace removal Commit a8fad0f broke the ERT tests by removing trailing whitespace inside the test strings. Fix the tests, and replace some line endings inside strings with explicit "\n" to avoid having further significant trailing whitespace in the code. --- rust-mode-tests.el | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-mode-tests.el b/rust-mode-tests.el index f255dbf1..54b4524d 100644 --- a/rust-mode-tests.el +++ b/rust-mode-tests.el @@ -246,8 +246,8 @@ fn bar() { }" 14 67)) "/** * */" - 8 - "This is a very very very very very very very long string" + 7 + " This is a very very very very very very very long string" "/** * This is a very very very very * very very very long string @@ -317,8 +317,7 @@ fn foo() { /*! * this is a nested doc comment */ - - //! And so is this + \n //! And so is this }")) (ert-deftest indent-inside-braces () From 55080f6744fc11b92016c3babcf4d35c2e4995a6 Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 01:59:20 -0500 Subject: [PATCH 2/4] 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 54b4524d..0df90604 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 dae685f3..70b49fea 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)) From 9c0846aa4580685b343921a7eefb0ccfd3f0633e Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 20:31:04 -0500 Subject: [PATCH 3/4] 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 0df90604..f4512f45 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))) From e6e16ccc21a64f4b333273f58a7bd6d0376f70f4 Mon Sep 17 00:00:00 2001 From: Micah Chalmer Date: Mon, 2 Feb 2015 20:37:16 -0500 Subject: [PATCH 4/4] 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 f4512f45..2b187282 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 {