]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/ruby-mode.el
Merge from origin/emacs-25
[gnu-emacs] / lisp / progmodes / ruby-mode.el
index c1001450bda388b5633a256cab33577fb85c80bd..d2370741972fd1a6e3f2a74239be23510bdec3ce 100644 (file)
@@ -431,17 +431,11 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
     (not (or (bolp)
              (memq (char-before) '(?\[ ?\())
              (and (memq (char-before)
-                        '(?\; ?- ?+ ?* ?/ ?: ?. ?, ?\\ ?& ?> ?< ?% ?~ ?^))
-                  ;; Not a binary operator symbol.
-                  (not (eq (char-before (1- (point))) ?:))
-                  ;; Not the end of a regexp or a percent literal.
-                  (not (memq (car (syntax-after (1- (point)))) '(7 15))))
-             (and (eq (char-before) ?\?)
-                  (equal (save-excursion (ruby-smie--backward-token)) "?"))
-             (and (eq (char-before) ?=)
-                  ;; Not a symbol :==, :!=, or a foo= method.
-                  (string-match "\\`\\s." (save-excursion
-                                            (ruby-smie--backward-token))))
+                        '(?\; ?- ?+ ?* ?/ ?: ?. ?, ?\\ ?& ?> ?< ?% ?~ ?^ ?= ??))
+                  ;; Not a binary operator symbol like :+ or :[]=.
+                  ;; Or a (method or symbol) name ending with ?.
+                  ;; Or the end of a regexp or a percent literal.
+                  (not (memq (car (syntax-after (1- (point)))) '(3 7 15))))
              (and (eq (char-before) ?|)
                   (member (save-excursion (ruby-smie--backward-token))
                           '("|" "||")))
@@ -454,7 +448,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
 
 (defun ruby-smie--redundant-do-p (&optional skip)
   (save-excursion
-    (if skip (backward-word-strictly 1))
+    (if skip (backward-word 1))
     (member (nth 2 (smie-backward-sexp ";")) '("while" "until" "for"))))
 
 (defun ruby-smie--opening-pipe-p ()
@@ -485,12 +479,16 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
                                              "else" "elsif" "do" "end" "and")
                                            'symbols))))
          (memq (car (syntax-after pos)) '(7 15))
-         (looking-at "[([]\\|[-+!~]\\sw\\|:\\(?:\\sw\\|\\s.\\)")))))
+         (looking-at "[([]\\|[-+!~:]\\(?:\\sw\\|\\s_\\)")))))
 
-(defun ruby-smie--at-dot-call ()
+(defun ruby-smie--before-method-name ()
+  ;; Only need to be accurate when method has keyword name.
   (and (eq ?w (char-syntax (following-char)))
-       (eq (char-before) ?.)
-       (not (eq (char-before (1- (point))) ?.))))
+       (or
+        (and
+         (eq (char-before) ?.)
+         (not (eq (char-before (1- (point))) ?.)))
+        (looking-back "^\\s *def\\s +\\=" (line-beginning-position)))))
 
 (defun ruby-smie--forward-token ()
   (let ((pos (point)))
@@ -511,17 +509,15 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
              (save-excursion
                (ruby-smie--args-separator-p (prog1 (point) (goto-char pos)))))
         " @ ")
-       ((looking-at ":\\s.+")
-        (goto-char (match-end 0)) (match-string 0)) ;bug#15208.
        ((looking-at "\\s\"") "")                    ;A string.
        (t
-        (let ((dot (ruby-smie--at-dot-call))
+        (let ((dot (ruby-smie--before-method-name))
               (tok (smie-default-forward-token)))
           (when dot
             (setq tok (concat "." tok)))
           (cond
            ((member tok '("unless" "if" "while" "until"))
-            (if (save-excursion (forward-word-strictly -1) (ruby-smie--bosp))
+            (if (save-excursion (forward-word -1) (ruby-smie--bosp))
                 tok "iuwu-mod"))
            ((string-match-p "\\`|[*&]?\\'" tok)
             (forward-char (- 1 (length tok)))
@@ -559,11 +555,9 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
       " @ ")
      (t
       (let ((tok (smie-default-backward-token))
-            (dot (ruby-smie--at-dot-call)))
+            (dot (ruby-smie--before-method-name)))
         (when dot
           (setq tok (concat "." tok)))
-        (when (and (eq ?: (char-before)) (string-match "\\`\\s." tok))
-          (forward-char -1) (setq tok (concat ":" tok))) ;; bug#15208.
         (cond
          ((member tok '("unless" "if" "while" "until"))
           (if (ruby-smie--bosp)
@@ -581,7 +575,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
          ((equal tok "do")
           (cond
            ((not (ruby-smie--redundant-do-p)) tok)
-           ((> (save-excursion (forward-word-strictly 1)
+           ((> (save-excursion (forward-word 1)
                                (forward-comment (point-max)) (point))
                (line-end-position))
             (ruby-smie--backward-token)) ;Fully redundant.
@@ -894,12 +888,18 @@ and `\\' when preceded by `?'."
           ((and (eq c ?:) (or (not b) (eq (char-syntax b) ? ))))
           ((eq c ?\\) (eq b ??)))))
 
-(defun ruby-singleton-class-p (&optional pos)
+(defun ruby-verify-heredoc (&optional pos)
   (save-excursion
     (when pos (goto-char pos))
-    (forward-word-strictly -1)
-    (and (or (bolp) (not (eq (char-before (point)) ?_)))
-         (looking-at ruby-singleton-class-re))))
+    ;; Not right after a symbol or prefix character.
+    ;; Method names are only allowed when separated by
+    ;; whitespace.  Not a limitation in Ruby, but it's hard for
+    ;; us to do better.
+    (when (not (memq (car (syntax-after (1- (point)))) '(2 3 6 10)))
+      (or (not (memq (char-before) '(?\s ?\t)))
+          (ignore (forward-word -1))
+          (eq (char-before) ?_)
+          (not (looking-at ruby-singleton-class-re))))))
 
 (defun ruby-expr-beg (&optional option)
   "Check if point is possibly at the beginning of an expression.
@@ -919,7 +919,7 @@ Can be one of `heredoc', `modifier', `expr-qstr', `expr-re'."
         nil)
        ((looking-at ruby-operator-re))
        ((eq option 'heredoc)
-        (and (< space 0) (not (ruby-singleton-class-p start))))
+        (and (< space 0) (ruby-verify-heredoc start)))
        ((or (looking-at "[\\[({,;]")
             (and (looking-at "[!?]")
                  (or (not (eq option 'modifier))
@@ -1240,7 +1240,7 @@ delimiter."
                     ((let ((s (ruby-parse-region (point) ruby-indent-point)))
                        (and (nth 2 s) (> (nth 2 s) 0)
                             (or (goto-char (cdr (nth 1 s))) t)))
-                     (forward-word-strictly -1)
+                     (forward-word -1)
                      (setq indent (ruby-indent-size (current-column)
                                                    (nth 2 state))))
                     (t
@@ -1259,7 +1259,7 @@ delimiter."
         (if (null (cdr (nth 1 state)))
             (error "Invalid nesting"))
         (goto-char (cdr (nth 1 state)))
-        (forward-word-strictly -1)               ; skip back a keyword
+        (forward-word -1)               ; skip back a keyword
         (setq begin (point))
         (cond
          ((looking-at "do\\>[^_]")      ; iter block is a special case
@@ -1352,7 +1352,7 @@ delimiter."
                                       (forward-char -1)
                                       (not (looking-at "{")))
                                     (progn
-                                      (forward-word-strictly -1)
+                                      (forward-word -1)
                                       (not (looking-at "do\\>[^_]")))))
                               (t t))))
                        (not (eq ?, c))
@@ -1505,11 +1505,10 @@ With ARG, do it many times.  Negative ARG means move backward."
                         (not (eq (char-before (point)) ?.))
                         (not (eq (char-before (point)) ?:)))
                    (ruby-end-of-block)
-                   (forward-word-strictly 1))
+                   (forward-word 1))
                   ((looking-at "\\(\\$\\|@@?\\)?\\sw")
                    (while (progn
-                            (while (progn (forward-word-strictly 1)
-                                          (looking-at "_")))
+                            (while (progn (forward-word 1) (looking-at "_")))
                             (cond ((looking-at "::") (forward-char 2) t)
                                   ((> (skip-chars-forward ".") 0))
                                   ((looking-at "\\?\\|!\\(=[~=>]\\|[^~=]\\)")
@@ -1525,7 +1524,7 @@ With ARG, do it many times.  Negative ARG means move backward."
                        (skip-chars-forward "<"))
                      (not expr))))
             (setq i (1- i)))
-        ((error) (forward-word-strictly 1)))
+        ((error) (forward-word 1)))
       i))))
 
 (defun ruby-backward-sexp (&optional arg)
@@ -1561,7 +1560,7 @@ With ARG, do it many times.  Negative ARG means move forward."
                   ((looking-at "\\s(") nil)
                   (t
                    (forward-char 1)
-                   (while (progn (forward-word-strictly -1)
+                   (while (progn (forward-word -1)
                                  (pcase (char-before)
                                    (`?_ t)
                                    (`?. (forward-char -1) t)
@@ -1848,18 +1847,22 @@ It will be properly highlighted even when the call omits parens.")
      (syntax-propertize-rules
       ;; $' $" $` .... are variables.
       ;; ?' ?" ?` are character literals (one-char strings in 1.9+).
-      ("\\([?$]\\)[#\"'`]"
+      ("\\([?$]\\)[#\"'`:?]"
        (1 (if (save-excursion
                 (nth 3 (syntax-ppss (match-beginning 0))))
               ;; Within a string, skip.
               (ignore
                (goto-char (match-end 1)))
-            (string-to-syntax "\\"))))
-      ;; Part of symbol when at the end of a method name.
+            (put-text-property (match-end 1) (match-end 0)
+                               'syntax-table (string-to-syntax "_"))
+            (string-to-syntax "'"))))
+      ;; Symbols with special characters.
+      ("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\)\\)"
+       (3 (string-to-syntax "_")))
+      ;; Part of method name when at the end of it.
       ("[!?]"
        (0 (unless (save-excursion
                     (or (nth 8 (syntax-ppss (match-beginning 0)))
-                        (eq (char-before) ?:)
                         (let (parse-sexp-lookup-properties)
                           (zerop (skip-syntax-backward "w_")))
                         (memq (preceding-char) '(?@ ?$))))
@@ -1894,14 +1897,14 @@ It will be properly highlighted even when the call omits parens.")
       ("^\\(=\\)begin\\_>" (1 "!"))
       ;; Handle here documents.
       ((concat ruby-here-doc-beg-re ".*\\(\n\\)")
-       (7 (unless (or (nth 8 (save-excursion
-                               (syntax-ppss (match-beginning 0))))
-                      (ruby-singleton-class-p (match-beginning 0)))
+       (7 (when (and (not (nth 8 (save-excursion
+                                   (syntax-ppss (match-beginning 0)))))
+                     (ruby-verify-heredoc (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)
+      ((concat "\\(?:^\\|[[ \t\n<+(,=*]\\)" ruby-percent-literal-beg-re)
        (1 (unless (nth 8 (save-excursion (syntax-ppss (match-beginning 1))))
             ;; Not inside a string, a comment, or a percent literal.
             (ruby-syntax-propertize-percent-literal end)
@@ -1920,7 +1923,7 @@ It will be properly highlighted even when the call omits parens.")
         (beginning-of-line)
         (while (re-search-forward ruby-here-doc-beg-re
                                   (line-end-position) t)
-          (unless (ruby-singleton-class-p (match-beginning 0))
+          (when (ruby-verify-heredoc (match-beginning 0))
             (push (concat (ruby-here-doc-end-match) "\n") res))))
       (save-excursion
         ;; With multiple openers on the same line, we don't know in which
@@ -2166,7 +2169,7 @@ See `font-lock-syntax-table'.")
      (1 font-lock-builtin-face))
     ;; Here-doc beginnings.
     (,ruby-here-doc-beg-re
-     (0 (unless (ruby-singleton-class-p (match-beginning 0))
+     (0 (when (ruby-verify-heredoc (match-beginning 0))
           'font-lock-string-face)))
     ;; Perl-ish keywords.
     "\\_<\\(?:BEGIN\\|END\\)\\_>\\|^__END__$"
@@ -2177,17 +2180,14 @@ See `font-lock-syntax-table'.")
     ;; Keywords that evaluate to certain values.
     ("\\_<__\\(?:LINE\\|ENCODING\\|FILE\\)__\\_>"
      (0 font-lock-builtin-face))
-    ;; Symbols with symbol characters.
+    ;; Symbols.
     ("\\(^\\|[^:]\\)\\(:@?\\(?:\\w\\|_\\)+\\)\\([!?=]\\)?"
      (2 font-lock-constant-face)
      (3 (unless (and (eq (char-before (match-end 3)) ?=)
                      (eq (char-after (match-end 3)) ?>))
-          ;; bug#18466
+          ;; bug#18644
           font-lock-constant-face)
         nil t))
-    ;; Symbols with special characters.
-    ("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
-     2 font-lock-constant-face)
     ;; Special globals.
     (,(concat "\\$\\(?:[:\"!@;,/\\._><\\$?~=*&`'+0-9]\\|-[0adFiIlpvw]\\|"
               (regexp-opt '("LOAD_PATH" "LOADED_FEATURES" "PROGRAM_NAME"
@@ -2227,7 +2227,7 @@ See `font-lock-syntax-table'.")
      1 font-lock-negation-char-face)
     ;; Character literals.
     ;; FIXME: Support longer escape sequences.
-    ("\\_<\\?\\\\?\\S " 0 font-lock-string-face)
+    ("\\?\\\\?\\_<.\\_>" 0 font-lock-string-face)
     ;; Regexp options.
     ("\\(?:\\s|\\|/\\)\\([imxo]+\\)"
      1 (when (save-excursion