emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/rust-mode 8c9ea88 127/486: Fix raw string bugs


From: ELPA Syncer
Subject: [nongnu] elpa/rust-mode 8c9ea88 127/486: Fix raw string bugs
Date: Sat, 7 Aug 2021 09:25:03 -0400 (EDT)

branch: elpa/rust-mode
commit 8c9ea8827dd2e894e852eeff0aa01588bb053991
Author: Micah Chalmer <micah@micahchalmer.net>
Commit: Micah Chalmer <micah@micahchalmer.net>

    Fix raw string bugs
---
 rust-mode-tests.el | 48 +++++++++++++++++++++++++++++++++++++
 rust-mode.el       | 70 ++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 108 insertions(+), 10 deletions(-)

diff --git a/rust-mode-tests.el b/rust-mode-tests.el
index e20e5fa..890ec77 100644
--- a/rust-mode-tests.el
+++ b/rust-mode-tests.el
@@ -963,6 +963,54 @@ list of substrings of `STR' each followed by its face."
      "r\"With a backslash at the end\\\"" font-lock-string-face
      "r##\"With two hashes\"##" font-lock-string-face)))
 
+(ert-deftest font-lock-raw-string-with-inner-hash ()
+  (rust-test-font-lock
+   "r##\"I've got an octothorpe (#)\"##; foo()"
+   '("r##\"I've got an octothorpe (#)\"##" font-lock-string-face)))
+
+(ert-deftest font-lock-string-ending-with-r-not-raw-string ()
+  (rust-test-font-lock
+   "fn f() {
+    \"Er\";
+}
+
+fn g() {
+    \"xs\";
+}"
+   '("fn" font-lock-keyword-face
+     "f" font-lock-function-name-face
+     "\"Er\"" font-lock-string-face
+     "fn" font-lock-keyword-face
+     "g" font-lock-function-name-face
+     "\"xs\"" font-lock-string-face)))
+
+(ert-deftest font-lock-raw-string-trick-ending-followed-by-string-with-quote ()
+  (rust-test-font-lock
+   "r\"With what looks like the start of a raw string at the end r#\";
+not_a_string();
+r##\"With \"embedded\" quote \"##;"
+   '("r\"With what looks like the start of a raw string at the end r#\"" 
font-lock-string-face
+     "r##\"With \"embedded\" quote \"##" font-lock-string-face)))
+
+(ert-deftest font-lock-raw-string-starter-inside-raw-string ()
+  ;; Check that it won't look for a raw string beginning inside another raw 
string.
+  (rust-test-font-lock
+   "r#\"In the first string r\" in the first string \"#;
+not_in_a_string();
+r##\"In the second string\"##;"
+   '("r#\"In the first string r\" in the first string \"#" 
font-lock-string-face
+     "r##\"In the second string\"##" font-lock-string-face)))
+
+(ert-deftest font-lock-raw-string-starter-inside-comment ()
+  ;; Check that it won't look for a raw string beginning inside another raw 
string.
+  (rust-test-font-lock
+   "// r\" this is a comment
+\"this is a string\";
+this_is_not_a_string();)"
+   '("// " font-lock-comment-delimiter-face
+     "r\" this is a comment\n" font-lock-comment-face
+     "\"this is a string\"" font-lock-string-face)))
+
 (ert-deftest indent-method-chains-no-align ()
   (let ((rust-indent-method-chain nil)) (test-indent
    "
diff --git a/rust-mode.el b/rust-mode.el
index fe9660b..29bb820 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -10,7 +10,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'misc))
+(eval-when-compile (require 'misc)
+                   (require 'rx))
 
 ;; for GNU Emacs < 24.3
 (eval-when-compile
@@ -51,13 +52,6 @@
 
     table))
 
-(defvar rust-mode-inside-raw-string-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/";)
@@ -318,6 +312,63 @@
              ("fn" . font-lock-function-name-face)
              ("static" . font-lock-constant-face)))))
 
+(defun rust-look-for-raw-string (bound)
+  ;; Find a raw string, but only if it's not in the middle of another string or
+  ;; a comment
+  
+  (let* ((raw-str-regexp
+          (rx
+           (seq
+            ;; The "r" starts the raw string.  Capture it as group 1 to mark 
it as such syntactically:
+            (group "r")
+
+            ;; Then either:
+            (or
+             ;; a sequence at least one "#" (followed by quote).  Capture all
+             ;; but the last "#" as group 2 for this case.
+             (seq (group (* "#")) "#\"")
+
+             ;; ...or a quote without any "#".  Capture it as group 3. This is
+             ;; used later to match the opposite quote only if this capture
+             ;; occurred
+             (group "\""))
+
+            ;; The contents of the string:
+            (*? anything)
+
+            ;; If there are any backslashes at the end of the string, capture
+            ;; them as group 4 so we can suppress the normal escape syntax
+            ;; parsing:
+            (group (* "\\"))
+
+            ;; Then the end of the string--the backreferences ensure that we
+            ;; only match the kind of ending that corresponds to the beginning
+            ;; we had:
+            (or
+             ;; There were "#"s - capture the last one as group 5 to mark it as
+             ;; the end of the string:
+             (seq "\"" (backref 2) (group "#"))
+
+             ;; No "#"s - capture the ending quote (using a backref to group 3,
+             ;; so that we can't match a quote if we had "#"s) as group 6
+             (group (backref 3))))))
+         ;; If it matches, it ends up with the starting character of the string
+         ;; as group 1, any ending backslashes as group 4, and the ending
+         ;; character as either group 5 or group 6.
+
+         (ret-list (save-excursion
+                    (let* ((match-end (re-search-forward raw-str-regexp bound 
t))
+                           (ret-list (and match-end (list match-end 
(match-beginning 0) (match-data) (point)))))
+                      (when (and ret-list
+                                 (save-excursion
+                                   (goto-char (nth 1 ret-list))
+                                   (not (rust-in-str-or-cmnt))))
+                        ret-list)))))
+    (when ret-list
+      (goto-char (nth 3 ret-list))
+      (set-match-data (nth 2 ret-list))
+      (nth 0 ret-list))))
+
 (defvar rust-mode-font-lock-syntactic-keywords
   (append
    ;; Handle single quoted character literals:
@@ -328,8 +379,7 @@
              "\\('\\)\\\\u[[:xdigit:]]\\{4\\}\\('\\)"
              "\\('\\)\\\\U[[:xdigit:]]\\{8\\}\\('\\)"))
    ;; Handle raw strings:
-   `(("\\(r\\)\"\\([^\"]*\\)\\(\"\\)" (1 "|") (2 
,rust-mode-inside-raw-string-syntax-table) (3 "|"))
-     ("\\(r\\)#\\(#*\\)\\(\"[^#]*\"\\2\\)\\(#\\)" (1 "|") (3 
,rust-mode-inside-raw-string-syntax-table) (4 "|")))))
+   `((rust-look-for-raw-string (1 "|") (4 "_" nil t) (5 "|" nil t) (6 "|" nil 
t)))))
 
 (defun rust-fill-prefix-for-comment-start (line-start)
   "Determine what to use for `fill-prefix' based on what is at the beginning 
of a line."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]