emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] /srv/bzr/emacs/trunk r112637: * lisp/progmodes/ruby-mode.e


From: Dmitry Gutov
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r112637: * lisp/progmodes/ruby-mode.el (ruby-expression-expansion-re): Allow to
Date: Sun, 19 May 2013 10:01:23 +0400
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 112637
committer: Dmitry Gutov <address@hidden>
branch nick: trunk
timestamp: Sun 2013-05-19 10:01:23 +0400
message:
  * lisp/progmodes/ruby-mode.el (ruby-expression-expansion-re): Allow to
  start at point, so that expansion starting right after opening
  slash in a regexp is recognized.
  (ruby-syntax-before-regexp-re): New defvar, extracted from
  ruby-syntax-propertize-function.  Since the value of this regexp
  is looked up at runtime now, we should be able to turn
  `ruby-syntax-methods-before-regexp' into a defcustom later.
  (ruby-syntax-propertize-function): Split regexp matching into two
  parts, for opening and closing slashes.  That allows us to skip
  over string interpolations and support multiline regexps.
  Don't call `ruby-syntax-propertize-expansions', instead use another rule
  for them, which calls `ruby-syntax-propertize-expansion'.
  (ruby-syntax-propertize-expansions): Move `remove-text-properties'
  call to `ruby-syntax-propertize-function'.
  (ruby-syntax-propertize-expansion): Extracted from
  `ruby-syntax-propertize-expansions'.  Handles one expansion.
  (ruby-syntax-propertize-heredoc): Explicitly call
  `ruby-syntax-propertize-expansions'.
  (ruby-syntax-propertize-percent-literal): Leave point right after
  the percent symbol, so that the expression expansion rule can
  propertize the contents.
  
  * test/automated/ruby-mode-tests.el (ruby-heredoc-highlights-interpolations)
  (ruby-regexp-skips-over-interpolation)
  (ruby-regexp-continues-till-end-when-unclosed)
  (ruby-regexp-can-be-multiline)
  (ruby-interpolation-inside-percent-literal): New tests.
  
  * test/indent/ruby.rb: Add multiline regexp example.
modified:
  lisp/ChangeLog
  lisp/progmodes/ruby-mode.el
  test/ChangeLog
  test/automated/ruby-mode-tests.el
  test/indent/ruby.rb
=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-05-18 23:18:16 +0000
+++ b/lisp/ChangeLog    2013-05-19 06:01:23 +0000
@@ -1,3 +1,27 @@
+2013-05-19  Dmitry Gutov  <address@hidden>
+
+       * progmodes/ruby-mode.el (ruby-expression-expansion-re): Allow to
+       start at point, so that expansion starting right after opening
+       slash in a regexp is recognized.
+       (ruby-syntax-before-regexp-re): New defvar, extracted from
+       ruby-syntax-propertize-function.  Since the value of this regexp
+       is looked up at runtime now, we should be able to turn
+       `ruby-syntax-methods-before-regexp' into a defcustom later.
+       (ruby-syntax-propertize-function): Split regexp matching into two
+       parts, for opening and closing slashes.  That allows us to skip
+       over string interpolations and support multiline regexps.
+       Don't call `ruby-syntax-propertize-expansions', instead use another rule
+       for them, which calls `ruby-syntax-propertize-expansion'.
+       (ruby-syntax-propertize-expansions): Move `remove-text-properties'
+       call to `ruby-syntax-propertize-function'.
+       (ruby-syntax-propertize-expansion): Extracted from
+       `ruby-syntax-propertize-expansions'.  Handles one expansion.
+       (ruby-syntax-propertize-heredoc): Explicitly call
+       `ruby-syntax-propertize-expansions'.
+       (ruby-syntax-propertize-percent-literal): Leave point right after
+       the percent symbol, so that the expression expansion rule can
+       propertize the contents.
+
 2013-05-18  Juri Linkov  <address@hidden>
 
        * man.el (Man-default-man-entry): Remove `-' from the end

=== modified file 'lisp/progmodes/ruby-mode.el'
--- a/lisp/progmodes/ruby-mode.el       2013-05-08 20:25:57 +0000
+++ b/lisp/progmodes/ruby-mode.el       2013-05-19 06:01:23 +0000
@@ -113,7 +113,7 @@
   "Regexp to match the beginning of a heredoc.")
 
   (defconst ruby-expression-expansion-re
-    
"[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)"))
+    
"\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)"))
 
 (defun ruby-here-doc-end-match ()
   "Return a regexp to find the end of a heredoc.
@@ -1360,11 +1360,26 @@
           '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
             "assert_match" "Given" "Then" "When")
           "Methods that can take regexp as the first argument.
-It will be properly highlighted even when the call omits parens."))
+It will be properly highlighted even when the call omits parens.")
+
+        (defvar ruby-syntax-before-regexp-re
+          (concat
+           ;; Special tokens that can't be followed by a division operator.
+           "\\(^\\|[[=(,~?:;<>]"
+           ;; Control flow keywords and operators following bol or whitespace.
+           "\\|\\(?:^\\|\\s \\)"
+           (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
+                         "or" "not" "&&" "||"))
+           ;; Method name from the list.
+           "\\|\\_<"
+           (regexp-opt ruby-syntax-methods-before-regexp)
+           "\\)\\s *")
+          "Regexp to match text that can be followed by a regular 
expression."))
 
       (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
@@ -1376,25 +1391,26 @@
                         ;; Not within a string.
                         (nth 3 (syntax-ppss (match-beginning 0))))
                 (string-to-syntax "\\"))))
-          ;; Regexps: regexps are distinguished from division because
-          ;; of the keyword, symbol, or method name before them.
-          ((concat
-            ;; Special tokens that can't be followed by a division operator.
-            "\\(^\\|[[=(,~?:;<>]"
-            ;; Control flow keywords and operators following bol or whitespace.
-            "\\|\\(?:^\\|\\s \\)"
-            (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
-                          "or" "not" "&&" "||"))
-            ;; Method name from the list.
-            "\\|\\_<"
-            (regexp-opt ruby-syntax-methods-before-regexp)
-            "\\)\\s *"
-            ;; The regular expression itself.
-            "\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)")
-           (3 (unless (nth 3 (syntax-ppss (match-beginning 2)))
-                (put-text-property (match-beginning 2) (match-end 2)
-                                   'syntax-table (string-to-syntax "\"/"))
-                (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.
@@ -1406,8 +1422,7 @@
           ;; Handle percent literals: %w(), %q{}, etc.
           ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
            (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
-         (point) end)
-        (ruby-syntax-propertize-expansions start end))
+         (point) end))
 
       (defun ruby-syntax-propertize-heredoc (limit)
         (let ((ppss (syntax-ppss))
@@ -1432,7 +1447,9 @@
                                        'syntax-table (string-to-syntax "\""))))
               ;; Make extra sure we don't move back, lest we could fall into an
               ;; inf-loop.
-              (if (< (point) start) (goto-char start))))))
+              (if (< (point) start)
+                  (goto-char start)
+                (ruby-syntax-propertize-expansions start (point)))))))
 
       (defun ruby-syntax-enclosing-percent-literal (limit)
         (let ((state (syntax-ppss))
@@ -1453,44 +1470,47 @@
                  (cl (or (cdr (aref (syntax-table) op))
                          (cdr (assoc op '((?< . ?>))))))
                  parse-sexp-lookup-properties)
-            (condition-case nil
-                (progn
-                  (if cl ; Paired delimiters.
-                      ;; Delimiter pairs of the same kind can be nested
-                      ;; inside the literal, as long as they are balanced.
-                      ;; Create syntax table that ignores other characters.
-                      (with-syntax-table (make-char-table 'syntax-table nil)
-                        (modify-syntax-entry op (concat "(" (char-to-string 
cl)))
-                        (modify-syntax-entry cl (concat ")" ops))
-                        (modify-syntax-entry ?\\ "\\")
-                        (save-restriction
-                          (narrow-to-region (point) limit)
-                          (forward-list))) ; skip to the paired character
-                    ;; Single character delimiter.
-                    (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
-                                               (regexp-quote ops)) limit nil))
-                  ;; Found the closing delimiter.
-                  (put-text-property (1- (point)) (point) 'syntax-table
-                                     (string-to-syntax "|")))
-              ;; Unclosed literal, leave the following text unpropertized.
-              ((scan-error search-failed) (goto-char limit))))))
+            (save-excursion
+              (condition-case nil
+                  (progn
+                    (if cl              ; Paired delimiters.
+                        ;; Delimiter pairs of the same kind can be nested
+                        ;; inside the literal, as long as they are balanced.
+                        ;; Create syntax table that ignores other characters.
+                        (with-syntax-table (make-char-table 'syntax-table nil)
+                          (modify-syntax-entry op (concat "(" (char-to-string 
cl)))
+                          (modify-syntax-entry cl (concat ")" ops))
+                          (modify-syntax-entry ?\\ "\\")
+                          (save-restriction
+                            (narrow-to-region (point) limit)
+                            (forward-list))) ; skip to the paired character
+                      ;; Single character delimiter.
+                      (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
+                                                 (regexp-quote ops)) limit 
nil))
+                    ;; Found the closing delimiter.
+                    (put-text-property (1- (point)) (point) 'syntax-table
+                                       (string-to-syntax "|")))
+                ;; Unclosed literal, do nothing.
+                ((scan-error search-failed)))))))
+
+      (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))))
+            (put-text-property beg (1+ beg) 'ruby-expansion-match-data
+                               (match-data))
+            (goto-char beg)
+            (while (re-search-forward "[\"`]" end 'move)
+              (put-text-property (match-beginning 0) (match-end 0)
+                                 'syntax-table (string-to-syntax "."))))))
 
       (defun ruby-syntax-propertize-expansions (start end)
-        (remove-text-properties start end '(ruby-expansion-match-data))
-        (goto-char start)
-        ;; Find all expression expansions and
-        ;; - save the match data to a text property, for font-locking later,
-        ;; - set the syntax of all double quotes and backticks to punctuation.
-        (while (re-search-forward ruby-expression-expansion-re end 'move)
-          (let ((beg (match-beginning 2))
-                (end (match-end 2)))
-            (when (and beg (save-excursion (nth 3 (syntax-ppss beg))))
-              (put-text-property beg (1+ beg) 'ruby-expansion-match-data
-                                 (match-data))
-              (goto-char beg)
-              (while (re-search-forward "[\"`]" end 'move)
-                (put-text-property (match-beginning 0) (match-end 0)
-                                   'syntax-table (string-to-syntax ".")))))))
+        (save-excursion
+          (goto-char start)
+          (while (re-search-forward ruby-expression-expansion-re end 'move)
+            (ruby-syntax-propertize-expansion))))
       )
 
   ;; For Emacsen where syntax-propertize-rules is not (yet) available,

=== modified file 'test/ChangeLog'
--- a/test/ChangeLog    2013-05-08 20:25:57 +0000
+++ b/test/ChangeLog    2013-05-19 06:01:23 +0000
@@ -1,3 +1,13 @@
+2013-05-19  Dmitry Gutov  <address@hidden>
+
+       * indent/ruby.rb: Add multiline regexp example.
+
+       * automated/ruby-mode-tests.el (ruby-heredoc-highlights-interpolations)
+       (ruby-regexp-skips-over-interpolation)
+       (ruby-regexp-continues-till-end-when-unclosed)
+       (ruby-regexp-can-be-multiline)
+       (ruby-interpolation-inside-percent-literal): New tests.
+
 2013-05-08  Stefan Monnier  <address@hidden>
 
        * indent/ruby.rb: Fix indentation after =; add more cases.

=== modified file 'test/automated/ruby-mode-tests.el'
--- a/test/automated/ruby-mode-tests.el 2013-04-15 23:07:14 +0000
+++ b/test/automated/ruby-mode-tests.el 2013-05-19 06:01:23 +0000
@@ -84,6 +84,9 @@
 (ert-deftest ruby-singleton-class-no-heredoc-font-lock ()
   (ruby-assert-face "class<<a" 8 nil))
 
+(ert-deftest ruby-heredoc-highlights-interpolations ()
+  (ruby-assert-face "s = <<EOS\n  #{foo}\nEOS" 15 
font-lock-variable-name-face))
+
 (ert-deftest ruby-deep-indent ()
   (let ((ruby-deep-arglist nil)
         (ruby-deep-indent-paren '(?\( ?\{ ?\[ ?\] t)))
@@ -109,6 +112,15 @@
 (ert-deftest ruby-regexp-starts-after-string ()
   (ruby-assert-state "'(/', /\d+/" 3 ?/ 8))
 
+(ert-deftest ruby-regexp-skips-over-interpolation ()
+  (ruby-assert-state "/#{foobs.join('/')}/" 3 nil))
+
+(ert-deftest ruby-regexp-continues-till-end-when-unclosed ()
+  (ruby-assert-state "/bars" 3 ?/))
+
+(ert-deftest ruby-regexp-can-be-multiline ()
+  (ruby-assert-state "/bars\ntees # toots \nfoos/" 3 nil))
+
 (ert-deftest ruby-indent-simple ()
   (ruby-should-indent-buffer
    "if foo
@@ -325,6 +337,13 @@
       (search-forward "tee")
       (should (string= (thing-at-point 'symbol) "tee")))))
 
+(ert-deftest ruby-interpolation-inside-percent-literal ()
+  (let ((s "%( #{boo} )"))
+    (ruby-assert-face s 1 font-lock-string-face)
+    (ruby-assert-face s 4 font-lock-variable-name-face)
+    (ruby-assert-face s 10 font-lock-string-face)
+    (ruby-assert-state s 8 nil)))
+
 (ert-deftest ruby-interpolation-inside-percent-literal-with-paren ()
   :expected-result :failed
   (let ((s "%(^#{\")\"}^)"))

=== modified file 'test/indent/ruby.rb'
--- a/test/indent/ruby.rb       2013-05-08 20:25:57 +0000
+++ b/test/indent/ruby.rb       2013-05-19 06:01:23 +0000
@@ -21,6 +21,11 @@
 # Highlight the regexp after "if".
 x = toto / foo if /do bar/ =~ "dobar"
 
+# Multiline regexp.
+/bars
+ tees # toots
+ nfoos/
+
 def test1(arg)
   puts "hello"
 end
@@ -47,6 +52,8 @@
   case a
   when "a"
     6
+  # Support for this syntax was removed in Ruby 1.9, so we
+  # probably don't need to handle it either.
   # when "b" :
   #   7
   # when "c" : 2


reply via email to

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