* lisp/progmodes/ruby-mode.el (ruby-smie-grammar): Add rule for formal
authorStefan Monnier <monnier@iro.umontreal.ca>
Thu, 29 Aug 2013 18:06:46 +0000 (14:06 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Thu, 29 Aug 2013 18:06:46 +0000 (14:06 -0400)
params of lambda expressions.
(ruby-smie--implicit-semi-p): Refine rule.
(ruby-smie--opening-pipe-p): New function.
(ruby-smie--forward-token, ruby-smie--backward-token): Handle Ruby
symbols and matched |...| for formal params.
(ruby-smie-rules): Don't let the formal params of a "do" prevent it
from being treated as hanging.  Handle "rescue".

Fixes: debbugs:15208

lisp/ChangeLog
lisp/progmodes/ruby-mode.el

index ec69915..3f95787 100644 (file)
@@ -1,3 +1,14 @@
+2013-08-29  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * progmodes/ruby-mode.el (ruby-smie-grammar): Add rule for formal
+       params of lambda expressions.
+       (ruby-smie--implicit-semi-p): Refine rule (bug#15208).
+       (ruby-smie--opening-pipe-p): New function.
+       (ruby-smie--forward-token, ruby-smie--backward-token): Handle Ruby
+       symbols and matched |...| for formal params.
+       (ruby-smie-rules): Don't let the formal params of a "do" prevent it
+       from being treated as hanging.  Handle "rescue".
+
 2013-08-29  Glenn Morris  <rgm@gnu.org>
 
        * progmodes/cc-engine.el (c-pull-open-brace):
index c8fae7b..7ecd207 100644 (file)
@@ -254,11 +254,13 @@ Also ignores spaces after parenthesis when 'space."
             ("for" for-body "end")
             ("[" expseq "]")
             ("{" hashvals "}")
+            ("{" insts "}")
             ("while" insts "end")
             ("until" insts "end")
             ("unless" insts "end")
             ("if" if-body "end")
             ("case"  cases "end"))
+      (formal-params ("opening-|" exp "|"))
       (for-body (for-head ";" insts))
       (for-head (id "in" exp))
       (cases (exp "then" insts) ;; FIXME: Ruby also allows (exp ":" insts).
@@ -285,10 +287,20 @@ Also ignores spaces after parenthesis when 'space."
   (save-excursion
     (skip-chars-backward " \t")
     (not (or (bolp)
-             (memq (char-before) '(?\; ?- ?+ ?* ?/ ?:))
+             (and (memq (char-before) '(?\; ?- ?+ ?* ?/ ?: ?.))
+                  ;; Make sure it's not the end of a regexp.
+                  (not (eq (car (syntax-after (1- (point)))) 7)))
              (and (memq (char-before) '(?\? ?=))
-                  (not (memq (char-syntax (char-before (1- (point))))
-                             '(?w ?_))))))))
+                  (let ((tok (ruby-smie--backward-token)))
+                    (or (equal tok "?")
+                        (string-match "\\`\\s." tok))))))))
+
+(defun ruby-smie--opening-pipe-p ()
+  (save-excursion
+    (if (eq ?| (char-before)) (forward-char -1))
+    (skip-chars-backward " \t\n")
+    (or (eq ?\{ (char-before))
+        (looking-back "\\_<do" (- (point) 2)))))
 
 (defun ruby-smie--forward-token ()
   (skip-chars-forward " \t")
@@ -299,12 +311,16 @@ Also ignores spaces after parenthesis when 'space."
         (if (eolp) (forward-char 1) (forward-comment 1))
         ";")
     (forward-comment (point-max))
+    (if (looking-at ":\\s.+")
+        (progn (goto-char (match-end 0)) (match-string 0)) ;; bug#15208.
     (let ((tok (smie-default-forward-token)))
       (cond
        ((member tok '("unless" "if" "while" "until"))
         (if (save-excursion (forward-word -1) (ruby-smie--bosp))
             tok "iuwu-mod"))
-       (t tok)))))
+         ((equal tok "|")
+          (if (ruby-smie--opening-pipe-p) "opening-|" tok))
+         (t tok))))))
 
 (defun ruby-smie--backward-token ()
   (let ((pos (point)))
@@ -314,10 +330,14 @@ Also ignores spaces after parenthesis when 'space."
         (progn (skip-chars-forward " \t")
                ";")
       (let ((tok (smie-default-backward-token)))
+        (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)
               tok "iuwu-mod"))
+         ((equal tok "|")
+          (if (ruby-smie--opening-pipe-p) "opening-|" tok))
          (t tok))))))
 
 (defun ruby-smie-rules (kind token)
@@ -332,7 +352,19 @@ Also ignores spaces after parenthesis when 'space."
        ;; For (invalid) code between switch and case.
        ;; (if (smie-parent-p "switch") 4)
        0))
-    (`(:before . ,(or `"else" `"then" `"elsif")) 0)
+    (`(:before . "do")
+     (when
+         (save-excursion
+           (forward-word 1)   ;Skip "do"
+           (skip-chars-forward " \t")
+           (and (equal (save-excursion (ruby-smie--forward-token)) "opening-|")
+                (save-excursion (forward-sexp 1)
+                                (skip-chars-forward " \t")
+                                (or (eolp)
+                                    (looking-at comment-start-skip)))))
+       ;; `(column . ,(smie-indent-virtual))
+       (smie-rule-parent)))
+    (`(:before . ,(or `"else" `"then" `"elsif" `"rescue")) 0)
     (`(:before . ,(or `"when"))
      (if (not (smie-rule-sibling-p)) 0)) ;; ruby-indent-level
     ;; Hack attack: Since newlines are separators, don't try to align args that