]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/progmodes/ruby-mode.el (ruby-syntax-expansion-allowed-p): New
authorDmitry Gutov <dgutov@yandex.ru>
Fri, 31 May 2013 06:04:33 +0000 (10:04 +0400)
committerDmitry Gutov <dgutov@yandex.ru>
Fri, 31 May 2013 06:04:33 +0000 (10:04 +0400)
function, checks if expression expansion is allowed in given parse
state.
(ruby-syntax-propertize-expansion): Use it.
(ruby-syntax-propertize-function): Bind `case-fold-search' to nil
around the body.

* test/automated/ruby-mode-tests.el: New tests, for percent literals
and expression expansion.

lisp/ChangeLog
lisp/progmodes/ruby-mode.el
test/ChangeLog
test/automated/ruby-mode-tests.el

index 87774cdb2a5fd5488b7286b98f4932c3912e446d..c4dc36245f23ad6c65b6e1ba773d751bd4acd6b5 100644 (file)
@@ -1,3 +1,12 @@
+2013-05-31  Dmitry Gutov  <dgutov@yandex.ru>
+
+       * progmodes/ruby-mode.el (ruby-syntax-expansion-allowed-p): New
+       function, checks if point is inside a literal that allows
+       expression expansion.
+       (ruby-syntax-propertize-expansion): Use it.
+       (ruby-syntax-propertize-function): Bind `case-fold-search' to nil
+       around the body.
+
 2013-05-30  Juri Linkov  <juri@jurta.org>
 
        * isearch.el (isearch-mode-map): Bind `isearch-toggle-invisible'
index a96ee64a22922d6e96f4eb6430b36c009a3cbe48..b7a635199abd5bb6d8dd3f2a23cae0fdafddc1a5 100644 (file)
@@ -1349,6 +1349,7 @@ If the result is do-end block, it will always be multiline."
 (declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit))
 ;; Unusual code layout confuses the byte-compiler.
 (declare-function ruby-syntax-propertize-expansion "ruby-mode" ())
+(declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state))
 
 (if (eval-when-compile (fboundp #'syntax-propertize-rules))
     ;; New code that works independently from font-lock.
@@ -1380,51 +1381,52 @@ It will be properly highlighted even when the call omits parens.")
 
       (defun ruby-syntax-propertize-function (start end)
         "Syntactic keywords for Ruby mode.  See `syntax-propertize-function'."
-        (goto-char start)
-        (remove-text-properties start end '(ruby-expansion-match-data))
-        (ruby-syntax-propertize-heredoc end)
-        (ruby-syntax-enclosing-percent-literal end)
-        (funcall
-         (syntax-propertize-rules
-          ;; $' $" $` .... are variables.
-          ;; ?' ?" ?` are ascii codes.
-          ("\\([?$]\\)[#\"'`]"
-           (1 (unless (save-excursion
-                        ;; Not within a string.
-                        (nth 3 (syntax-ppss (match-beginning 0))))
-                (string-to-syntax "\\"))))
-          ;; Regular expressions.  Start with matching unescaped slash.
-          ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
-           (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
-                (when (or
-                       ;; Beginning of a regexp.
-                       (and (null (nth 8 state))
-                            (save-excursion
-                              (forward-char -1)
-                              (looking-back ruby-syntax-before-regexp-re
-                                            (point-at-bol))))
-                       ;; End of regexp.  We don't match the whole
-                       ;; regexp at once because it can have
-                       ;; string interpolation inside, or span
-                       ;; several lines.
-                       (eq ?/ (nth 3 state)))
-                  (string-to-syntax "\"/")))))
-          ;; Expression expansions in strings.  We're handling them
-          ;; here, so that the regexp rule never matches inside them.
-          (ruby-expression-expansion-re
-           (0 (ignore (ruby-syntax-propertize-expansion))))
-          ("^=en\\(d\\)\\_>" (1 "!"))
-          ("^\\(=\\)begin\\_>" (1 "!"))
-          ;; Handle here documents.
-          ((concat ruby-here-doc-beg-re ".*\\(\n\\)")
-           (7 (unless (ruby-singleton-class-p (match-beginning 0))
-                (put-text-property (match-beginning 7) (match-end 7)
-                                   'syntax-table (string-to-syntax "\""))
-                (ruby-syntax-propertize-heredoc end))))
-          ;; Handle percent literals: %w(), %q{}, etc.
-          ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
-           (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
-         (point) end))
+        (let (case-fold-search)
+          (goto-char start)
+          (remove-text-properties start end '(ruby-expansion-match-data))
+          (ruby-syntax-propertize-heredoc end)
+          (ruby-syntax-enclosing-percent-literal end)
+          (funcall
+           (syntax-propertize-rules
+            ;; $' $" $` .... are variables.
+            ;; ?' ?" ?` are ascii codes.
+            ("\\([?$]\\)[#\"'`]"
+             (1 (unless (save-excursion
+                          ;; Not within a string.
+                          (nth 3 (syntax-ppss (match-beginning 0))))
+                  (string-to-syntax "\\"))))
+            ;; Regular expressions.  Start with matching unescaped slash.
+            ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
+             (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
+                  (when (or
+                         ;; Beginning of a regexp.
+                         (and (null (nth 8 state))
+                              (save-excursion
+                                (forward-char -1)
+                                (looking-back ruby-syntax-before-regexp-re
+                                              (point-at-bol))))
+                         ;; End of regexp.  We don't match the whole
+                         ;; regexp at once because it can have
+                         ;; string interpolation inside, or span
+                         ;; several lines.
+                         (eq ?/ (nth 3 state)))
+                    (string-to-syntax "\"/")))))
+            ;; Expression expansions in strings.  We're handling them
+            ;; here, so that the regexp rule never matches inside them.
+            (ruby-expression-expansion-re
+             (0 (ignore (ruby-syntax-propertize-expansion))))
+            ("^=en\\(d\\)\\_>" (1 "!"))
+            ("^\\(=\\)begin\\_>" (1 "!"))
+            ;; Handle here documents.
+            ((concat ruby-here-doc-beg-re ".*\\(\n\\)")
+             (7 (unless (ruby-singleton-class-p (match-beginning 0))
+                  (put-text-property (match-beginning 7) (match-end 7)
+                                     'syntax-table (string-to-syntax "\""))
+                  (ruby-syntax-propertize-heredoc end))))
+            ;; Handle percent literals: %w(), %q{}, etc.
+            ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
+             (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
+           (point) end)))
 
       (defun ruby-syntax-propertize-heredoc (limit)
         (let ((ppss (syntax-ppss))
@@ -1496,9 +1498,10 @@ It will be properly highlighted even when the call omits parens.")
       (defun ruby-syntax-propertize-expansion ()
         ;; Save the match data to a text property, for font-locking later.
         ;; Set the syntax of all double quotes and backticks to punctuation.
-        (let ((beg (match-beginning 2))
-              (end (match-end 2)))
-          (when (and beg (save-excursion (nth 3 (syntax-ppss beg))))
+        (let* ((beg (match-beginning 2))
+               (end (match-end 2))
+               (state (and beg (save-excursion (syntax-ppss beg)))))
+          (when (ruby-syntax-expansion-allowed-p state)
             (put-text-property beg (1+ beg) 'ruby-expansion-match-data
                                (match-data))
             (goto-char beg)
@@ -1506,6 +1509,17 @@ It will be properly highlighted even when the call omits parens.")
               (put-text-property (match-beginning 0) (match-end 0)
                                  'syntax-table (string-to-syntax "."))))))
 
+      (defun ruby-syntax-expansion-allowed-p (parse-state)
+        "Return non-nil if expression expansion is allowed."
+        (let ((term (nth 3 parse-state)))
+          (cond
+           ((memq term '(?\" ?` ?\n)))
+           ((eq term t)
+            (save-match-data
+              (save-excursion
+                (goto-char (nth 8 parse-state))
+                (looking-at "%\\(?:[QWrx]\\|\\W\\)")))))))
+
       (defun ruby-syntax-propertize-expansions (start end)
         (save-excursion
           (goto-char start)
index 56e019ec4af374cd9013e7236e1a6070ef8e4c63..98fb2e3da1f8a473b8fc4d2838f8741166f3e47a 100644 (file)
@@ -1,3 +1,8 @@
+2013-05-31  Dmitry Gutov  <dgutov@yandex.ru>
+
+       * automated/ruby-mode-tests.el: New tests, for percent literals
+       and expression expansion.
+
 2013-05-29  Leo Liu  <sdl.web@gmail.com>
 
        * indent/octave.m: Tweak.
index e52927a2968be4823717da3946238ca856e3c5f7..6ed2a8ad377c4ee6e7c073ca7c22574777d22242 100644 (file)
@@ -353,6 +353,23 @@ VALUES-PLIST is a list with alternating index and value elements."
     ;; It's confused by the closing paren in the middle.
     (ruby-assert-state s 8 nil)))
 
+(ert-deftest ruby-interpolation-inside-double-quoted-percent-literals ()
+  (ruby-assert-face "%Q{foo #@bar}" 8 font-lock-variable-name-face)
+  (ruby-assert-face "%W{foo #@bar}" 8 font-lock-variable-name-face)
+  (ruby-assert-face "%r{foo #@bar}" 8 font-lock-variable-name-face)
+  (ruby-assert-face "%x{foo #@bar}" 8 font-lock-variable-name-face))
+
+(ert-deftest ruby-no-interpolation-in-single-quoted-literals ()
+  (ruby-assert-face "'foo #@bar'" 7 font-lock-string-face)
+  (ruby-assert-face "%q{foo #@bar}" 8 font-lock-string-face)
+  (ruby-assert-face "%w{foo #@bar}" 8 font-lock-string-face)
+  (ruby-assert-face "%s{foo #@bar}" 8 font-lock-string-face))
+
+(ert-deftest ruby-no-unknown-percent-literals ()
+  ;; No folding of case.
+  (ruby-assert-face "%S{foo}" 4 nil)
+  (ruby-assert-face "%R{foo}" 4 nil))
+
 (ert-deftest ruby-add-log-current-method-examples ()
   (let ((pairs '(("foo" . "#foo")
                  ("C.foo" . ".foo")