Commits

graaff  committed 3305759

Sync to upsteam 1.8.5_pre4.

  • Participants
  • Parent commits 93696d4

Comments (0)

Files changed (9)

+2009-07-19  Hans de Graaff  <graaff@xemacs.org>
+
+	* Sync with upstream 1.8.5_pre4
+
+	* ruby-electric.el: New.
+
 2003-10-31  Norbert Koch  <viteno@xemacs.org>
 
 	* Makefile (VERSION): XEmacs package 1.02 released.
 # Boston, MA 02111-1307, USA.
 
 VERSION = 1.02
-AUTHOR_VERSION = 1.6.8
-MAINTAINER = Hans de Graaff <hans@degraaff.org>
+AUTHOR_VERSION = 1.8.5_pre4
+MAINTAINER = Hans de Graaff <graaff@xemacs.org>
 PACKAGE = ruby-modes
 PKG_TYPE = regular
 REQUIRES = xemacs-base debug
 CATEGORY = standard
 
-ELCS = inf-ruby.elc ruby-mode.elc rubydb3x.elc
+ELCS = inf-ruby.elc ruby-electric.elc ruby-mode.elc rubydb3x.elc
 
 EXTRA_SOURCES = README
 
 README		this file
 inf-ruby.el	program to run ruby under emacs
+ruby-electric.el	electric minor mode for ruby
 ruby-mode.el	ruby mode for emacs
-rubydb2x.el	ruby debugger support for emacs 19.2x or before
 rubydb3x.el	ruby debugger support for emacs 19.3x or later
 ;;;     for example :
 ;;;
 ;;;    (autoload 'ruby-mode "ruby-mode"
-;;;      "Mode for editing ruby source files")
+;;;      "Mode for editing ruby source files" t)
 ;;;    (setq auto-mode-alist
 ;;;          (append '(("\\.rb$" . ruby-mode)) auto-mode-alist))
 ;;;    (setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
 ;;;    				     interpreter-mode-alist))
 ;;;    
-;;; (2) set to road inf-ruby and set inf-ruby key definition in ruby-mode.
+;;; (2) set to load inf-ruby and set inf-ruby key definition in ruby-mode.
 ;;;
 ;;;    (autoload 'run-ruby "inf-ruby"
 ;;;      "Run an inferior Ruby process")
 ;;; HISTORY
 ;;; senda -  8 Apr 1998: Created.
 ;;;	 $Log$
-;;;	 Revision 1.3.2.3  2002/09/07 14:37:26  nobu
+;;;	 Revision 1.6.2.1  2004/07/27 07:51:28  matz
+;;;	 * object.c (Init_Object): "===" calls rb_obj_equal() directly.
+;;;	   [ruby-list:39937]
+;;;	
+;;;	 Revision 1.6  2002/09/07 14:35:46  nobu
 ;;;	 * misc/inf-ruby.el (inferior-ruby-error-regexp-alist): regexp
 ;;;	   alist for error message from ruby.
 ;;;	
 ;;;	   doesn't parse first line, so insert separators before each
 ;;;	   evaluations.
 ;;;	
-;;;	 Revision 1.3.2.2  2002/08/19 10:06:20  nobu
+;;;	 Revision 1.5  2002/08/19 10:05:47  nobu
 ;;;	 * misc/inf-ruby.el (inf-ruby-keys): ruby-send-definition
 ;;;	   conflicted with ruby-insert-end.
-;;;
+;;;	
 ;;;	 * misc/inf-ruby.el (inferior-ruby-mode): compilation-minor-mode.
-;;;
+;;;	
 ;;;	 * misc/inf-ruby.el (ruby-send-region): send as here document to
 ;;;	   adjust source file/line.  [ruby-talk:47113], [ruby-dev:17965]
-;;;
+;;;	
 ;;;	 * misc/inf-ruby.el (ruby-send-terminator): added to make unique
 ;;;	   terminator.
-;;;
+;;;	
+;;;	 Revision 1.4  2002/01/29 07:16:09  matz
+;;;	 * file.c (rb_stat_rdev_major): added. [new]
+;;;	
+;;;	 * file.c (rb_stat_rdev_minor): added. [new]
+;;;	
+;;;	 * file.c (rb_stat_inspect): print mode in octal.
+;;;	
 ;;;	 Revision 1.3  1999/12/01 09:24:18  matz
 ;;;	 19991201
 ;;;	

File inf-ruby.el.upstream

 ;;;    (setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
 ;;;    				     interpreter-mode-alist))
 ;;;    
-;;; (2) set to road inf-ruby and set inf-ruby key definition in ruby-mode.
+;;; (2) set to load inf-ruby and set inf-ruby key definition in ruby-mode.
 ;;;
 ;;;    (autoload 'run-ruby "inf-ruby"
 ;;;      "Run an inferior Ruby process")
 ;;; HISTORY
 ;;; senda -  8 Apr 1998: Created.
 ;;;	 $Log$
-;;;	 Revision 1.3.2.3  2002/09/07 14:37:26  nobu
+;;;	 Revision 1.6.2.1  2004/07/27 07:51:28  matz
+;;;	 * object.c (Init_Object): "===" calls rb_obj_equal() directly.
+;;;	   [ruby-list:39937]
+;;;	
+;;;	 Revision 1.6  2002/09/07 14:35:46  nobu
 ;;;	 * misc/inf-ruby.el (inferior-ruby-error-regexp-alist): regexp
 ;;;	   alist for error message from ruby.
 ;;;	
 ;;;	   doesn't parse first line, so insert separators before each
 ;;;	   evaluations.
 ;;;	
-;;;	 Revision 1.3.2.2  2002/08/19 10:06:20  nobu
+;;;	 Revision 1.5  2002/08/19 10:05:47  nobu
 ;;;	 * misc/inf-ruby.el (inf-ruby-keys): ruby-send-definition
 ;;;	   conflicted with ruby-insert-end.
 ;;;	
 ;;;	 * misc/inf-ruby.el (ruby-send-terminator): added to make unique
 ;;;	   terminator.
 ;;;	
-;;;	 Revision 1.3.2.1  2002/02/01 06:01:51  matz
-;;;	 * re.c (rb_reg_search): should set regs.allocated.
+;;;	 Revision 1.4  2002/01/29 07:16:09  matz
+;;;	 * file.c (rb_stat_rdev_major): added. [new]
+;;;	
+;;;	 * file.c (rb_stat_rdev_minor): added. [new]
+;;;	
+;;;	 * file.c (rb_stat_inspect): print mode in octal.
 ;;;	
 ;;;	 Revision 1.3  1999/12/01 09:24:18  matz
 ;;;	 19991201

File package-info.in

    filename FILENAME
    md5sum MD5SUM
    size SIZE
-   provides (inf-ruby ruby-mode rubydb)
+   provides (inf-ruby ruby-electric ruby-mode rubydb)
    requires (REQUIRES)
    type regular
 ))

File ruby-electric.el

+;; -*-Emacs-Lisp-*-
+;;
+;; ruby-electric.el --- electric editing commands for ruby files
+;;
+;; Copyright (C) 2005 by Dee Zsombor <dee dot zsombor at gmail dot com>.
+;; Released under same license terms as Ruby.
+;;
+;; Due credit: this work was inspired by a code snippet posted by
+;; Frederick Ros at http://rubygarden.org/ruby?EmacsExtensions.
+;;
+;; Following improvements where added:
+;;
+;;       - handling of strings of type 'here document'
+;;       - more keywords, with special handling for 'do'
+;;       - packaged into a minor mode
+;;
+;; Usage:
+;;
+;;    0) copy ruby-electric.el into directory where emacs can find it.
+;;
+;;    1) modify your startup file (.emacs or whatever) by adding
+;;       following line:
+;;
+;;            (require 'ruby-electric)
+;;
+;;       note that you need to have font lock enabled beforehand.
+;;
+;;    2) toggle Ruby Electric Mode on/off with ruby-electric-mode.
+;;
+;; Changelog:
+;;
+;;  2005/Jan/14: inserts matching pair delimiters like {, [, (, ', ",
+;;  ' and | .
+;;
+;;  2005/Jan/14: added basic Custom support for configuring keywords
+;;  with electric closing.
+;;
+;;  2005/Jan/18: more Custom support for configuring characters for
+;;  which matching expansion should occur.
+;;
+;;  2005/Jan/18: no longer uses 'looking-back' or regexp character
+;;  classes like [:space:] since they are not implemented on XEmacs.
+;;
+;;  2005/Feb/01: explicitly provide default argument of 1 to
+;;  'backward-word' as it requires it on Emacs 21.3
+;;
+;;  2005/Mar/06: now stored inside ruby CVS; customize pages now have
+;;  ruby as parent; cosmetic fixes.
+
+
+(require 'ruby-mode)
+
+(defgroup ruby-electric nil
+  "Minor mode providing electric editing commands for ruby files"
+  :group 'ruby) 
+
+(defconst ruby-electric-expandable-do-re
+  "do\\s-$")
+
+(defconst ruby-electric-expandable-bar
+  "\\s-\\(do\\|{\\)\\s-+|")
+
+(defvar ruby-electric-matching-delimeter-alist
+  '((?\[ . ?\])
+    (?\( . ?\))
+    (?\' . ?\')
+    (?\` . ?\`)
+    (?\" . ?\")))
+
+(defcustom ruby-electric-simple-keywords-re 
+  "\\(def\\|if\\|class\\|module\\|unless\\|case\\|while\\|do\\|until\\|for\\|begin\\)"
+  "*Regular expresion matching keywords for which closing 'end'
+is to be inserted."
+  :type 'regexp :group 'ruby-electric)
+
+(defcustom ruby-electric-expand-delimiters-list '(all)
+  "*List of contexts where matching delimiter should be
+inserted. The word 'all' will do all insertions."
+  :type '(set :extra-offset 8
+	      (const :tag "Everything" all )
+	      (const :tag "Curly brace" ?\{ )
+	      (const :tag "Square brace" ?\[ )
+	      (const :tag "Round brace" ?\( )
+	      (const :tag "Quote" ?\' )
+	      (const :tag "Double quote" ?\" )
+	      (const :tag "Back quote" ?\` )
+	      (const :tag "Vertical bar" ?\| ))
+  :group 'ruby-electric) 
+
+(defcustom ruby-electric-newline-before-closing-bracket nil
+  "*Controls whether a newline should be inserted before the
+closing bracket or not."
+  :type 'boolean :group 'ruby-electric)
+
+;;;###autoload (autoload 'ruby-electric-mode "ruby-electric" "Toggle Ruby Electric minor mode" t)
+(define-minor-mode ruby-electric-mode
+  "Toggle Ruby Electric minor mode.
+With no argument, this command toggles the mode.  Non-null prefix
+argument turns on the mode.  Null prefix argument turns off the
+mode.
+
+When Ruby Electric mode is enabled, an indented 'end' is
+heuristicaly inserted whenever typing a word like 'module',
+'class', 'def', 'if', 'unless', 'case', 'until', 'for', 'begin',
+'do'. Simple, double and back quotes as well as braces are paired
+auto-magically. Expansion does not occur inside comments and
+strings. Note that you must have Font Lock enabled."
+  ;; initial value.
+  nil
+  ;;indicator for the mode line.
+  " REl"
+  ;;keymap
+  ruby-mode-map
+  (ruby-electric-setup-keymap))
+
+(defun ruby-electric-setup-keymap()
+  (define-key ruby-mode-map " " 'ruby-electric-space)
+  (define-key ruby-mode-map "{" 'ruby-electric-curlies)
+  (define-key ruby-mode-map "(" 'ruby-electric-matching-char)
+  (define-key ruby-mode-map "[" 'ruby-electric-matching-char)
+  (define-key ruby-mode-map "\"" 'ruby-electric-matching-char)
+  (define-key ruby-mode-map "\'" 'ruby-electric-matching-char)
+  (define-key ruby-mode-map "|" 'ruby-electric-bar))
+
+(defun ruby-electric-space (arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (if (ruby-electric-space-can-be-expanded-p)
+      (save-excursion
+	(ruby-indent-line t)
+	(newline)
+	(ruby-insert-end))))
+
+(defun ruby-electric-code-at-point-p()
+  (and ruby-electric-mode
+       (let* ((properties (text-properties-at (point))))
+	 (and (null (memq 'font-lock-string-face properties))
+	      (null (memq 'font-lock-comment-face properties))))))
+
+(defun ruby-electric-string-at-point-p()
+  (and ruby-electric-mode
+       (consp (memq 'font-lock-string-face (text-properties-at (point))))))
+
+(defun ruby-electric-is-last-command-char-expandable-punct-p()
+  (or (memq 'all ruby-electric-expand-delimiters-list)
+      (memq last-command-char ruby-electric-expand-delimiters-list))) 
+
+(defun ruby-electric-space-can-be-expanded-p()
+  (if (ruby-electric-code-at-point-p)
+      (let* ((ruby-electric-keywords-re 
+	      (concat ruby-electric-simple-keywords-re "\\s-$"))
+	     (ruby-electric-single-keyword-in-line-re 
+	      (concat "\\s-*" ruby-electric-keywords-re)))
+	(save-excursion
+	  (backward-word 1)
+	  (or (looking-at ruby-electric-expandable-do-re)
+	      (and (looking-at ruby-electric-keywords-re)
+		   (not (string= "do" (match-string 1)))
+		   (progn
+		     (beginning-of-line)
+		     (looking-at ruby-electric-single-keyword-in-line-re))))))))
+
+
+(defun ruby-electric-curlies(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (if (ruby-electric-is-last-command-char-expandable-punct-p)
+      (cond ((ruby-electric-code-at-point-p)
+	     (insert " ")
+	     (save-excursion
+	       (if ruby-electric-newline-before-closing-bracket
+		   (newline))
+	       (insert "}")))
+	    ((ruby-electric-string-at-point-p)
+	     (save-excursion
+	       (backward-char 1)
+	       (when (char-equal ?\# (preceding-char))
+		 (forward-char 1)
+		 (insert "}")))))))
+
+(defun ruby-electric-matching-char(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (and (ruby-electric-is-last-command-char-expandable-punct-p)
+       (ruby-electric-code-at-point-p)
+       (save-excursion
+	 (insert (cdr (assoc last-command-char 
+			     ruby-electric-matching-delimeter-alist))))))
+
+(defun ruby-electric-bar(arg)
+  (interactive "P")
+  (self-insert-command (prefix-numeric-value arg))
+  (and (ruby-electric-is-last-command-char-expandable-punct-p)
+       (ruby-electric-code-at-point-p)
+       (and (save-excursion (re-search-backward ruby-electric-expandable-bar nil t))
+	    (= (point) (match-end 0))) ;looking-back is missing on XEmacs
+       (save-excursion 
+	 (insert "|"))))
+
+(provide 'ruby-electric)
+
+;;; ruby-electric.el ends here

File ruby-mode.el

 
 (defconst ruby-block-end-re "end")
 
+(defconst ruby-here-doc-beg-re
+  "<<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
+
+(defun ruby-here-doc-end-match ()
+  (concat "^"
+	  (if (match-string 1) "[ \t]*" nil)
+	  (regexp-quote
+	   (or (match-string 3)
+	       (match-string 4)
+	       (match-string 5)))))
+
 (defconst ruby-delimiter
-  (concat "[?$/%(){}#\"'`.:]\\|\\[\\|\\]\\|\\<\\("
+  (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
 	  ruby-block-beg-re
 	  "\\|" ruby-block-end-re
-	  "\\)\\>\\|^=begin")
+	  "\\)\\>\\|^=begin\\|" ruby-here-doc-beg-re)
   )
 
 (defconst ruby-negative
   (define-key ruby-mode-map "}" 'ruby-electric-brace)
   (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun)
   (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun)
-  (define-key ruby-mode-map "\e\C-b" 'ruby-beginning-of-block)
-  (define-key ruby-mode-map "\e\C-f" 'ruby-end-of-block)
+  (define-key ruby-mode-map "\e\C-b" 'ruby-backward-sexp)
+  (define-key ruby-mode-map "\e\C-f" 'ruby-forward-sexp)
   (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block)
   (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block)
   (define-key ruby-mode-map "\e\C-h" 'ruby-mark-defun)
+  (define-key ruby-mode-map "\e\C-q" 'ruby-indent-exp)
   (define-key ruby-mode-map "\t" 'ruby-indent-command)
   (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end)
   (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent)
   (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table)
   )
 
+(defcustom ruby-indent-tabs-mode nil
+  "*Indentation can insert tabs in ruby mode if this is non-nil."
+  :type 'boolean :group 'ruby)
+
+(defcustom ruby-indent-level 2
+  "*Indentation of ruby statements."
+  :type 'integer :group 'ruby)
+
+(defcustom ruby-comment-column 32
+  "*Indentation column of comments."
+  :type 'integer :group 'ruby)
+
+(defcustom ruby-deep-arglist t
+  "*Deep indent lists in parenthesis when non-nil.
+Also ignores spaces after parenthesis when 'space."
+  :group 'ruby)
+
+(defcustom ruby-deep-indent-paren '(?\( ?\[ ?\] t)
+  "*Deep indent lists in parenthesis when non-nil. t means continuous line.
+Also ignores spaces after parenthesis when 'space."
+  :group 'ruby)
+
+(defcustom ruby-deep-indent-paren-style 'space
+  "Default deep indent style."
+  :options '(t nil space) :group 'ruby)
+
 (eval-when-compile (require 'cl))
+(defun ruby-imenu-create-index-in-block (prefix beg end)
+  (let ((index-alist '()) (case-fold-search nil)
+	name next pos decl sing)
+    (goto-char beg)
+    (while (re-search-forward "^\\s *\\(\\(class\\>\\(\\s *<<\\)?\\|module\\>\\)\\s *\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\>\\s *\\([^\(\n ]+\\)\\)" end t)
+      (setq sing (match-beginning 3))
+      (setq decl (match-string 5))
+      (setq next (match-end 0))
+      (setq name (or (match-string 4) (match-string 6)))
+      (setq pos (match-beginning 0))
+      (cond
+       ((string= "alias" decl)
+	(if prefix (setq name (concat prefix name)))
+	(push (cons name pos) index-alist))
+       ((string= "def" decl)
+	(if prefix
+	    (setq name
+		  (cond
+		   ((string-match "^self\." name)
+		    (concat (substring prefix 0 -1) (substring name 4)))
+		  (t (concat prefix name)))))
+	(push (cons name pos) index-alist)
+	(ruby-accurate-end-of-block end))
+       (t
+	(if (string= "self" name)
+	    (if prefix (setq name (substring prefix 0 -1)))
+	  (if prefix (setq name (concat (substring prefix 0 -1) "::" name)))
+	  (push (cons name pos) index-alist))
+	(ruby-accurate-end-of-block end)
+	(setq beg (point))
+	(setq index-alist
+	      (nconc (ruby-imenu-create-index-in-block
+		      (concat name (if sing "." "#"))
+		      next beg) index-alist))
+	(goto-char beg))))
+    index-alist))
+
 (defun ruby-imenu-create-index ()
-  (let ((index-alist '())
-	class-name class-begin method-name method-begin decl)
-    (goto-char (point-min))
-    (while (re-search-forward "^\\s *\\(class\\|def\\)\\s *\\([^(\n ]+\\)" nil t)
-      (setq decl (buffer-substring (match-beginning 1) (match-end 1)))
-      (cond
-       ((string= "class" decl)
-	(setq class-begin (match-beginning 2))
-	(setq class-name (buffer-substring class-begin (match-end 2)))
-	(push (cons class-name (match-beginning 0)) index-alist)
-	(ruby-mark-defun)
-	(save-restriction
-	  (narrow-to-region (region-beginning) (region-end))
-         (while (re-search-forward "^\\s *def\\s *\\([^(\n ]+\\)" nil 'move)
-	    (setq method-begin (match-beginning 1))
-	    (setq method-name (buffer-substring method-begin (match-end 1)))
-	    (push (cons (concat class-name "#" method-name) (match-beginning 0)) index-alist))))
-       ((string= "def" decl)
-	(setq method-begin (match-beginning 2))
-	(setq method-name (buffer-substring method-begin (match-end 2)))
-	(push (cons method-name (match-beginning 0)) index-alist))))
-    index-alist))
+  (nreverse (ruby-imenu-create-index-in-block nil (point-min) nil)))
+
+(defun ruby-accurate-end-of-block (&optional end)
+  (let (state)
+    (or end (setq end (point-max)))
+    (while (and (setq state (apply 'ruby-parse-partial end state))
+		(>= (nth 2 state) 0) (< (point) end)))))
 
 (defun ruby-mode-variables ()
   (set-syntax-table ruby-mode-syntax-table)
   (make-variable-buffer-local 'comment-end)
   (setq comment-end "")
   (make-variable-buffer-local 'comment-column)
-  (setq comment-column 32)
+  (setq comment-column ruby-comment-column)
   (make-variable-buffer-local 'comment-start-skip)
-  (setq comment-start-skip "\\(^\\|\\s-\\);?#+ *")
+  (setq comment-start-skip "#+ *")
+  (setq indent-tabs-mode ruby-indent-tabs-mode)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq parse-sexp-ignore-comments t)
   (make-local-variable 'paragraph-start)
   (make-local-variable 'imenu-create-index-function)
   (setq imenu-create-index-function 'ruby-imenu-create-index)
 
+  (make-local-variable 'add-log-current-defun-function)
+  (setq add-log-current-defun-function 'ruby-add-log-current-method)
+
   (run-hooks 'ruby-mode-hook))
 
 (defun ruby-current-indentation ()
 	  (indent-to x)
 	  (move-to-column (+ x shift))))))
 
+(defun ruby-special-char-p (&optional pnt)
+  (setq pnt (or pnt (point)))
+  (let ((c (char-before pnt)) (b (and (< (point-min) pnt) (char-before (1- pnt)))))
+    (cond ((or (eq c ??) (eq c ?$)))
+	  ((and (eq c ?:) (or (not b) (eq (char-syntax b) ? ))))
+	  ((eq c ?\\) (eq b ??)))))
+
 (defun ruby-expr-beg (&optional option)
   (save-excursion
     (store-match-data nil)
-    (skip-chars-backward " \t")
-    (cond
-     ((bolp) t)
-     ((looking-at "\\?")
-      (or (bolp) (forward-char -1))
-      (not (looking-at "\\sw")))
-     (t
-      (forward-char -1)
-      (or (looking-at ruby-operator-re)
-	  (looking-at "[\\[({,;]")
-	  (and (not (eq option 'modifier))
-	       (looking-at "[!?]"))
-	  (and (looking-at ruby-symbol-re)
-	       (skip-chars-backward ruby-symbol-chars)
-	       (cond
-		((or (looking-at ruby-block-beg-re)
-		     (looking-at ruby-block-op-re)
-		     (looking-at ruby-block-mid-re))
-		 (goto-char (match-end 0))
-		 (looking-at "\\>"))
-		(t
-		 (and (not (eq option 'expr-arg))
-		      (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))))))))))
+    (let ((space (skip-chars-backward " \t"))
+	  (start (point)))
+      (cond
+       ((bolp) t)
+       ((progn
+	  (forward-char -1)
+	  (and (looking-at "\\?")
+	       (or (eq (char-syntax (char-before (point))) ?w)
+		   (ruby-special-char-p))))
+	nil)
+       ((and (eq option 'heredoc) (< space 0)) t)
+       ((or (looking-at ruby-operator-re)
+	    (looking-at "[\\[({,;]")
+	    (and (looking-at "[!?]")
+		 (or (not (eq option 'modifier))
+		     (bolp)
+		     (save-excursion (forward-char -1) (looking-at "\\Sw$"))))
+	    (and (looking-at ruby-symbol-re)
+		 (skip-chars-backward ruby-symbol-chars)
+		 (cond
+		  ((or (looking-at (concat "\\<\\(" ruby-block-beg-re
+					   "|" ruby-block-op-re
+					   "|" ruby-block-mid-re "\\)\\>")))
+		   (goto-char (match-end 0))
+		   (not (looking-at "\\s_")))
+		  ((eq option 'expr-qstr)
+		   (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]"))
+		  ((eq option 'expr-re)
+		   (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))
+		  (t nil)))))))))
 
 (defun ruby-forward-string (term &optional end no-error expand)
   (let ((n 1) (c (string-to-char term))
       (forward-char -1))
     (cond ((zerop n))
 	  (no-error nil)
-	  (error "unterminated string"))))
+	  ((error "unterminated string")))))
 
-(defun ruby-parse-region (start end)
-  (let ((indent-point end)
-	  (indent 0)
-	  (in-string nil)
-	  (in-paren nil)
-	  (depth 0)
-	  (nest nil)
-	  (pcol nil))
-    (save-excursion
-	(if start
-	    (goto-char start)
-	  (ruby-beginning-of-indent))
-	(save-restriction
-	  (narrow-to-region (point) end)
-	  (while (and (> indent-point (point))
-		      (re-search-forward ruby-delimiter indent-point t))
-	    (or depth (setq depth 0))
-	    (let ((pnt (point)) w re expand)
-	      (goto-char (match-beginning 0))
-	      (cond
-	       ((or (looking-at "\"")	;skip string
-		    (looking-at "`"))
-		(cond
-		 ((and (not (eobp))
-		       (ruby-forward-string (buffer-substring (point) (1+ (point))) indent-point t t))
-		  nil)
-		 (t
-		  (setq in-string (point))
-		  (goto-char indent-point))))
-	       ((looking-at "'")
-		(cond
-		 ((and (not (eobp))
-		       (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" indent-point t))
-		  nil)
-		 (t
-		  (setq in-string (point))
-		  (goto-char indent-point))))
-	       ((looking-at "/")
-		(cond
-		 ((and (not (eobp)) (ruby-expr-beg))
-		  (if (ruby-forward-string "/" indent-point t t)
-		      nil
-		    (setq in-string (point))
-		    (goto-char indent-point)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "%")
-		(cond
-		 ((and (not (eobp)) (ruby-expr-beg 'expr-arg)
-		       (not (looking-at "%="))
-		       (looking-at "%[Qqrxw]?\\(.\\)"))
-		  (goto-char (match-beginning 1))
-		  (setq expand (not (eq (char-before) ?q)))
-		  (setq w (buffer-substring (match-beginning 1)
-					    (match-end 1)))
-		  (cond
-		   ((string= w "[") (setq re "]["))
-		   ((string= w "{") (setq re "}{"))
-		   ((string= w "(") (setq re ")("))
-		   ((string= w "<") (setq re "><"))
-		   ((or (and expand (string= w "\\"))
-			(member w '("*" "." "+" "?" "^" "$")))
-		    (setq w (concat "\\" w))))
-		  (unless (cond (re (ruby-forward-string re indent-point t expand))
-				(expand (ruby-forward-string w indent-point t t))
-				(t (re-search-forward
-				    (if (string= w "\\")
-					"\\\\[^\\]*\\\\"
-				      (concat "[^\\]\\(\\\\\\\\\\)*" w))
-				    indent-point t)))
-		    (setq in-string (point))
-		    (goto-char indent-point)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "\\?")	;skip ?char
-		(cond
-		 ((ruby-expr-beg)
-		  (looking-at "?\\(\\\\C-\\|\\\\M-\\)*.")
-		  (goto-char (match-end 0)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "\\$")	;skip $char
-		(goto-char pnt)
-		(forward-char 1))
-	       ((looking-at "#")	;skip comment
-		(forward-line 1)
-		(goto-char (point))
-		)
-	       ((looking-at "(")
+(defun ruby-deep-indent-paren-p (c)
+  (cond ((listp ruby-deep-indent-paren)
+	 (let ((deep (assoc c ruby-deep-indent-paren)))
+	   (cond (deep
+		  (or (cdr deep) ruby-deep-indent-paren-style))
+		 ((memq c ruby-deep-indent-paren)
+		  ruby-deep-indent-paren-style))))
+	((eq c ruby-deep-indent-paren) ruby-deep-indent-paren-style)
+	((eq c ?\( ) ruby-deep-arglist)))
+
+(defun ruby-parse-partial (&optional end in-string nest depth pcol indent)
+  (or depth (setq depth 0))
+  (or indent (setq indent 0))
+  (when (re-search-forward ruby-delimiter end 'move)
+    (let ((pnt (point)) w re expand)
+      (goto-char (match-beginning 0))
+      (cond
+       ((and (memq (char-before) '(?@ ?$)) (looking-at "\\sw"))
+	(goto-char pnt))
+       ((looking-at "[\"`]")		;skip string
+	(cond
+	 ((and (not (eobp))
+	       (ruby-forward-string (buffer-substring (point) (1+ (point))) end t t))
+	  nil)
+	 (t
+	  (setq in-string (point))
+	  (goto-char end))))
+       ((looking-at "'")
+	(cond
+	 ((and (not (eobp))
+	       (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" end t))
+	  nil)
+	 (t
+	  (setq in-string (point))
+	  (goto-char end))))
+       ((looking-at "/")
+	(cond
+	 ((and (not (eobp)) (ruby-expr-beg 'expr-re))
+	  (if (ruby-forward-string "/" end t t)
+	      nil
+	    (setq in-string (point))
+	    (goto-char end)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "%")
+	(cond
+	 ((and (not (eobp))
+	       (ruby-expr-beg 'expr-qstr)
+	       (not (looking-at "%="))
+	       (looking-at "%[QqrxWw]?\\([^a-zA-Z0-9 \t\n]\\)"))
+	  (goto-char (match-beginning 1))
+	  (setq expand (not (memq (char-before) '(?q ?w))))
+	  (setq w (match-string 1))
+	  (cond
+	   ((string= w "[") (setq re "]["))
+	   ((string= w "{") (setq re "}{"))
+	   ((string= w "(") (setq re ")("))
+	   ((string= w "<") (setq re "><"))
+	   ((and expand (string= w "\\"))
+	    (setq w (concat "\\" w))))
+	  (unless (cond (re (ruby-forward-string re end t expand))
+			(expand (ruby-forward-string w end t t))
+			(t (re-search-forward
+			    (if (string= w "\\")
+				"\\\\[^\\]*\\\\"
+			      (concat "[^\\]\\(\\\\\\\\\\)*" w))
+			    end t)))
+	    (setq in-string (point))
+	    (goto-char end)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "\\?")		;skip ?char
+	(cond
+	 ((and (ruby-expr-beg)
+	       (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?."))
+	  (goto-char (match-end 0)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "\\$")		;skip $char
+	(goto-char pnt)
+	(forward-char 1))
+       ((looking-at "#")		;skip comment
+	(forward-line 1)
+	(goto-char (point))
+	)
+       ((looking-at "[\\[{(]")
+	(let ((deep (ruby-deep-indent-paren-p (char-after))))
+	  (if (and deep (or (not (eq (char-after) ?\{)) (ruby-expr-beg)))
+	      (progn
+		(and (eq deep 'space) (looking-at ".\\s +[^# \t\n]")
+		     (setq pnt (1- (match-end 0))))
 		(setq nest (cons (cons (char-after (point)) pnt) nest))
 		(setq pcol (cons (cons pnt depth) pcol))
-		(setq depth 0)
-		(goto-char pnt)
-		)
-	       ((looking-at "[\\[{]")
-		(setq nest (cons (cons (char-after (point)) pnt) nest))
-		(setq depth (1+ depth))
-		(goto-char pnt)
-		)
-	       ((looking-at ")")
-		(setq nest (cdr nest))
-		(setq depth (cdr (car pcol)))
-		(setq pcol (cdr pcol))
-		(goto-char pnt))
-	       ((looking-at "[])}]")
-		(setq nest (cdr nest))
-		(setq depth (1- depth))
-		(goto-char pnt))
-	       ((looking-at ruby-block-end-re)
-		(if (or (and (not (bolp))
-			     (progn
-			       (forward-char -1)
-			       (setq w (char-after (point)))
-			       (or (eq ?_ w)
-				   (eq ?. w))))
-			(progn
-			  (goto-char pnt)
-			  (setq w (char-after (point)))
-			  (or (eq ?_ w)
-			      (eq ?! w)
-			      (eq ?? w))))
-		    nil
-		  (setq nest (cdr nest))
-		  (setq depth (1- depth)))
-		(goto-char pnt))
-	       ((looking-at "def\\s +[^(\n;]*")
-		(if (or (bolp)
-			(progn
-			  (forward-char -1)
-			  (not (eq ?_ (char-after (point))))))
-		    (progn
-		      (setq nest (cons (cons nil pnt) nest))
-		      (setq depth (1+ depth))))
-		(goto-char (match-end 0)))
-	       ((looking-at ruby-block-beg-re)
-		(and
-		 (save-match-data
-                   (or (not (looking-at "do\\>[^_]"))
-                       (save-excursion
-                         (back-to-indentation)
-			 (not (looking-at ruby-non-block-do-re)))))
-		 (or (bolp)
+		(setq depth 0))
+	    (setq nest (cons (cons (char-after (point)) pnt) nest))
+	    (setq depth (1+ depth))))
+	(goto-char pnt)
+	)
+       ((looking-at "[])}]")
+	(if (ruby-deep-indent-paren-p (matching-paren (char-after)))
+	    (setq depth (cdr (car pcol)) pcol (cdr pcol))
+	  (setq depth (1- depth)))
+	(setq nest (cdr nest))
+	(goto-char pnt))
+       ((looking-at (concat "\\<\\(" ruby-block-end-re "\\)\\>"))
+	(if (or (and (not (bolp))
 		     (progn
 		       (forward-char -1)
 		       (setq w (char-after (point)))
-		       (not (or (eq ?_ w)
-				(eq ?. w)))))
-		 (goto-char pnt)
-		 (setq w (char-after (point)))
-		 (not (eq ?_ w))
-		 (not (eq ?! w))
-		 (not (eq ?? w))
-		 (skip-chars-forward " \t")
-		 (goto-char (match-beginning 0))
-		 (or (not (looking-at ruby-modifier-re))
-		     (ruby-expr-beg 'modifier))
-		 (goto-char pnt)
-		 (setq nest (cons (cons nil pnt) nest))
-		 (setq depth (1+ depth)))
-		(goto-char pnt))
-	       ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*\\)?")
-		(goto-char (match-end 0)))
-	       ((or (looking-at "\\.")
-		    (looking-at "\\.\\.\\.?")
-		    (looking-at "\\.[0-9]+")
-		    (looking-at "\\.[a-zA-Z_0-9]+"))
-		(goto-char (match-end 0)))
-	       ((looking-at "^=begin")
-		(if (re-search-forward "^=end" indent-point t)
-		    (forward-line 1)
-		  (setq in-string (match-end 0))
-		  (goto-char indent-point)))
-	       (t
-		(error (format "bad string %s"
-			       (buffer-substring (point) pnt)
-			       )))))))
-	(list in-string (car nest) depth (car (car pcol))))))
+		       (or (eq ?_ w)
+			   (eq ?. w))))
+		(progn
+		  (goto-char pnt)
+		  (setq w (char-after (point)))
+		  (or (eq ?_ w)
+		      (eq ?! w)
+		      (eq ?? w))))
+	    nil
+	  (setq nest (cdr nest))
+	  (setq depth (1- depth)))
+	(goto-char pnt))
+       ((looking-at "def\\s +[^(\n;]*")
+	(if (or (bolp)
+		(progn
+		  (forward-char -1)
+		  (not (eq ?_ (char-after (point))))))
+	    (progn
+	      (setq nest (cons (cons nil pnt) nest))
+	      (setq depth (1+ depth))))
+	(goto-char (match-end 0)))
+       ((looking-at (concat "\\<\\(" ruby-block-beg-re "\\)\\>"))
+	(and
+	 (save-match-data
+	   (or (not (looking-at "do\\>[^_]"))
+	       (save-excursion
+		 (back-to-indentation)
+		 (not (looking-at ruby-non-block-do-re)))))
+	 (or (bolp)
+	     (progn
+	       (forward-char -1)
+	       (setq w (char-after (point)))
+	       (not (or (eq ?_ w)
+			(eq ?. w)))))
+	 (goto-char pnt)
+	 (setq w (char-after (point)))
+	 (not (eq ?_ w))
+	 (not (eq ?! w))
+	 (not (eq ?? w))
+	 (skip-chars-forward " \t")
+	 (goto-char (match-beginning 0))
+	 (or (not (looking-at ruby-modifier-re))
+	     (ruby-expr-beg 'modifier))
+	 (goto-char pnt)
+	 (setq nest (cons (cons nil pnt) nest))
+	 (setq depth (1+ depth)))
+	(goto-char pnt))
+       ((looking-at ":\\(['\"]\\)\\(\\\\.\\|[^\\\\]\\)*\\1")
+	(goto-char (match-end 0)))
+       ((looking-at ":\\([-,.+*/%&|^~<>]=?\\|===?\\|<=>\\)")
+	(goto-char (match-end 0)))
+       ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*[!?=]?\\)?")
+	(goto-char (match-end 0)))
+       ((or (looking-at "\\.\\.\\.?")
+	    (looking-at "\\.[0-9]+")
+	    (looking-at "\\.[a-zA-Z_0-9]+")
+	    (looking-at "\\."))
+	(goto-char (match-end 0)))
+       ((looking-at "^=begin")
+	(if (re-search-forward "^=end" end t)
+	    (forward-line 1)
+	  (setq in-string (match-end 0))
+	  (goto-char end)))
+       ((looking-at "<<")
+	(cond
+	 ((and (ruby-expr-beg 'heredoc)
+	       (looking-at "<<\\(-\\)?\\(\\([\"'`]\\)\\([^\n]+?\\)\\3\\|\\sw+\\)"))
+	  (setq re (regexp-quote (or (match-string 4) (match-string 2))))
+	  (if (match-beginning 1) (setq re (concat "\\s *" re)))
+	  (let* ((id-end (goto-char (match-end 0)))
+		 (line-end-position (save-excursion (end-of-line) (point)))
+		 (state (list in-string nest depth pcol indent)))
+	    ;; parse the rest of the line
+	    (while (and (> line-end-position (point))
+			(setq state (apply 'ruby-parse-partial
+					   line-end-position state))))
+	    (setq in-string (car state)
+		  nest (nth 1 state)
+		  depth (nth 2 state)
+		  pcol (nth 3 state)
+		  indent (nth 4 state))
+	    ;; skip heredoc section
+	    (if (re-search-forward (concat "^" re "$") end 'move)
+		(forward-line 1)
+	      (setq in-string id-end)
+	      (goto-char end))))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "^__END__$")
+	(goto-char pnt))
+       ((looking-at ruby-here-doc-beg-re)
+	(if (re-search-forward (ruby-here-doc-end-match)
+			       indent-point t)
+	    (forward-line 1)
+	  (setq in-string (match-end 0))
+	  (goto-char indent-point)))
+       (t
+	(error (format "bad string %s"
+		       (buffer-substring (point) pnt)
+		       ))))))
+  (list in-string nest depth pcol))
+
+(defun ruby-parse-region (start end)
+  (let (state)
+    (save-excursion
+      (if start
+	  (goto-char start)
+	(ruby-beginning-of-indent))
+      (save-restriction
+	(narrow-to-region (point) end)
+	(while (and (> end (point))
+		    (setq state (apply 'ruby-parse-partial end state))))))
+    (list (nth 0 state)			; in-string
+	  (car (nth 1 state))		; nest
+	  (nth 2 state)			; depth
+	  (car (car (nth 3 state)))	; pcol
+	  ;(car (nth 5 state))		; indent
+	  )))
 
 (defun ruby-indent-size (pos nest)
-  (+ pos (* (if nest nest 1) ruby-indent-level)))
+  (+ pos (* (or nest 1) ruby-indent-level)))
 
 (defun ruby-calculate-indent (&optional parse-start)
   (save-excursion
     (beginning-of-line)
     (let ((indent-point (point))
-	    (case-fold-search nil)
-	    state bol eol
-	    (indent 0))
-	(if parse-start
-	    (goto-char parse-start)
-	  (ruby-beginning-of-indent)
-	  (setq parse-start (point)))
-	(back-to-indentation)
-	(setq indent (current-column))
-	(setq state (ruby-parse-region parse-start indent-point))
+	  (case-fold-search nil)
+	  state bol eol begin op-end
+	  (paren (progn (skip-syntax-forward " ")
+			(and (char-after) (matching-paren (char-after)))))
+	  (indent 0))
+      (if parse-start
+	  (goto-char parse-start)
+	(ruby-beginning-of-indent)
+	(setq parse-start (point)))
+      (back-to-indentation)
+      (setq indent (current-column))
+      (setq state (ruby-parse-region parse-start indent-point))
+      (cond
+       ((nth 0 state)			; within string
+	(setq indent nil))		;  do nothing
+       ((car (nth 1 state))		; in paren
+	(goto-char (setq begin (cdr (nth 1 state))))
+	(let ((deep (ruby-deep-indent-paren-p (car (nth 1 state)))))
+	  (if deep
+	      (cond ((and (eq deep t) (eq (car (nth 1 state)) paren))
+		     (skip-syntax-backward " ")
+		     (setq indent (1- (current-column))))
+		    ((let ((s (ruby-parse-region (point) indent-point)))
+		       (and (nth 2 s) (> (nth 2 s) 0)
+			    (or (goto-char (cdr (nth 1 s))) t)))
+		     (forward-word -1)
+		     (setq indent (ruby-indent-size (current-column) (nth 2 state))))
+		    (t
+		     (setq indent (current-column))
+		     (cond ((eq deep 'space))
+			   (paren (setq indent (1- indent)))
+			   (t (setq indent (ruby-indent-size (1- indent) 1))))))
+	    (if (nth 3 state) (goto-char (nth 3 state))
+	      (goto-char parse-start) (back-to-indentation))
+	    (setq indent (ruby-indent-size (current-column) (nth 2 state))))
+	  (and (eq (car (nth 1 state)) paren)
+	       (ruby-deep-indent-paren-p (matching-paren paren))
+	       (search-backward (char-to-string paren))
+	       (setq indent (current-column)))))
+       ((and (nth 2 state) (> (nth 2 state) 0)) ; in nest
+	(if (null (cdr (nth 1 state)))
+	    (error "invalid nest"))
+	(goto-char (cdr (nth 1 state)))
+	(forward-word -1)		; skip back a keyword
+	(setq begin (point))
 	(cond
-	 ((nth 0 state)			; within string
-	  (setq indent nil))		;  do nothing
-	 ((car (nth 1 state))		; in paren
-	  (goto-char (cdr (nth 1 state)))
-	  (if (eq (car (nth 1 state)) ?\( )
-	      (let ((column (current-column))
-		    (s (ruby-parse-region (point) indent-point)))
-		(cond
-		 ((and (nth 2 s) (> (nth 2 s) 0))
-		  (goto-char (cdr (nth 1 s)))
-		  (forward-word -1)
-		  (setq indent (ruby-indent-size (current-column) (nth 2 state))))
-		 (t
-		  (setq indent (current-column)))))
-	    (cond
-	     ((nth 3 state)
-	      (goto-char (nth 3 state))
-	      (setq indent (ruby-indent-size (current-column) (nth 2 state))))
-	     (t
-	      (goto-char parse-start)
-	      (back-to-indentation)
-	      (setq indent (ruby-indent-size (current-column) (nth 2 state)))))
-	    ))
-	 ((and (nth 2 state)(> (nth 2 state) 0)) ; in nest
-	  (if (null (cdr (nth 1 state)))
-	      (error "invalid nest"))
-	  (goto-char (cdr (nth 1 state)))
-	  (forward-word -1)		; skip back a keyword
-	  (cond
-	   ((looking-at "do\\>[^_]")	; iter block is a special case
-	    (cond
-	     ((nth 3 state)
-	      (goto-char (nth 3 state))
-	      (setq indent (ruby-indent-size (current-column) (nth 2 state))))
-	     (t
-	      (goto-char parse-start)
-	      (back-to-indentation)
-	      (setq indent (ruby-indent-size (current-column) (nth 2 state))))))
-	   (t
-	    (setq indent (+ (current-column) ruby-indent-level)))))
-
-	 ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest
-	  (setq indent (ruby-indent-size (current-column) (nth 2 state)))))
-
+	 ((looking-at "do\\>[^_]")	; iter block is a special case
+	  (if (nth 3 state) (goto-char (nth 3 state))
+	    (goto-char parse-start) (back-to-indentation))
+	  (setq indent (ruby-indent-size (current-column) (nth 2 state))))
+	 (t
+	  (setq indent (+ (current-column) ruby-indent-level)))))
+       
+       ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest
+	(setq indent (ruby-indent-size (current-column) (nth 2 state)))))
+      (when indent
+	(goto-char indent-point)
+	(end-of-line)
+	(setq eol (point))
+	(beginning-of-line)
 	(cond
-	 (indent
-	  (goto-char indent-point)
+	 ((and (not (ruby-deep-indent-paren-p paren))
+	       (re-search-forward ruby-negative eol t))
+	  (and (not (eq ?_ (char-after (match-end 0))))
+	       (setq indent (- indent ruby-indent-level))))
+	 ((and
+	   (save-excursion
+	     (beginning-of-line)
+	     (not (bobp)))
+	   (or (ruby-deep-indent-paren-p t)
+	       (null (car (nth 1 state)))))
+	  ;; goto beginning of non-empty no-comment line
+	  (let (end done)
+	    (while (not done)
+	      (skip-chars-backward " \t\n")
+	      (setq end (point))
+	      (beginning-of-line)
+	      (if (re-search-forward "^\\s *#" end t)
+		  (beginning-of-line)
+		(setq done t))))
+	  (setq bol (point))
 	  (end-of-line)
-	  (setq eol (point))
-	  (beginning-of-line)
-	  (cond
-	   ((re-search-forward ruby-negative eol t)
-	    (and (not (eq ?_ (char-after (match-end 0))))
-		 (setq indent (- indent ruby-indent-level))))
-	   ;;operator terminated lines
-	   ((and
-	     (save-excursion
-	       (beginning-of-line)
-	       (not (bobp)))
-	     (or (null (car (nth 1 state))) ;not in parens
-		 (and (eq (car (nth 1 state)) ?\{)
-		      (save-excursion	;except non-block braces
-			(goto-char (cdr (nth 1 state)))
-			(or (bobp) (forward-char -1))
-			(not (ruby-expr-beg))))))
-	    ;; goto beginning of non-empty no-comment line
-	    (let (end done)
-	      (while (not done)
-		(skip-chars-backward " \t\n")
-		(setq end (point))
-		(beginning-of-line)
-		(if (re-search-forward "^\\s *#" end t)
-		    (beginning-of-line)
-		  (setq done t))))
-	    (setq bol (point))
-	    (end-of-line)
+	  ;; skip the comment at the end
+	  (skip-chars-backward " \t")
+	  (let (end (pos (point)))
+	    (beginning-of-line)
+	    (while (and (re-search-forward "#" pos t)
+			(setq end (1- (point)))
+			(or (ruby-special-char-p end)
+			    (and (setq state (ruby-parse-region parse-start end))
+				 (nth 0 state))))
+	      (setq end nil))
+	    (goto-char (or end pos))
 	    (skip-chars-backward " \t")
-	    (let ((pos (point)))
-	      (while (and (re-search-backward "#" bol t)
-			  (eq (char-before) ??))
-		(forward-char -1))
-	      (skip-chars-backward " \t")
-	      (and
-	       (setq state (ruby-parse-region parse-start (point)))
-	       (nth 0 state)
-	       (goto-char pos)))
-	    (or (bobp) (forward-char -1))
-	    (and
-	     (or (and (looking-at ruby-symbol-re)
-		      (skip-chars-backward ruby-symbol-chars)
-		      (looking-at ruby-block-hanging-re)
-		      (not (eq (point) (nth 3 state)))
-		      (save-excursion
-			(goto-char (match-end 0))
-			(not (looking-at "[a-z_]"))))
-		 (and (looking-at ruby-operator-re)
-		      (not (eq (char-after (1- (point))) ??))
-		      (not (eq (char-after (1- (point))) ?$))
-		      (or (not (eq ?/ (char-after (point))))
-			  (null (nth 0 (ruby-parse-region parse-start (point)))))
-		      (or (not (eq ?| (char-after (point))))
-			  (save-excursion
-			    (or (eolp) (forward-char -1))
-			    (cond
-			     ((search-backward "|" nil t)
-			      (skip-chars-backward " \t\n")
-			      (and (not (eolp))
-				   (progn
-				     (forward-char -1)
-				     (not (looking-at "{")))
-				   (progn
-				     (forward-word -1)
-				     (not (looking-at "do\\>[^_]")))))
-			     (t t))))))
-	     (setq indent (+ indent ruby-indent-level)))))))
-	indent)))
+	    (setq begin (if (nth 0 state) pos (cdr (nth 1 state))))
+	    (setq state (ruby-parse-region parse-start (point))))
+	  (or (bobp) (forward-char -1))
+	  (and
+	   (or (and (looking-at ruby-symbol-re)
+		    (skip-chars-backward ruby-symbol-chars)
+		    (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>"))
+		    (not (eq (point) (nth 3 state)))
+		    (save-excursion
+		      (goto-char (match-end 0))
+		      (not (looking-at "[a-z_]"))))
+	       (and (looking-at ruby-operator-re)
+		    (not (ruby-special-char-p))
+		    ;; operator at the end of line
+		    (let ((c (char-after (point))))
+		      (and
+;; 		       (or (null begin)
+;; 			   (save-excursion
+;; 			     (goto-char begin)
+;; 			     (skip-chars-forward " \t")
+;; 			     (not (or (eolp) (looking-at "#")
+;; 				      (and (eq (car (nth 1 state)) ?{)
+;; 					   (looking-at "|"))))))
+		       (or (not (eq ?/ c))
+			   (null (nth 0 (ruby-parse-region (or begin parse-start) (point)))))
+		       (or (not (eq ?| (char-after (point))))
+			   (save-excursion
+			     (or (eolp) (forward-char -1))
+			     (cond
+			      ((search-backward "|" nil t)
+			       (skip-chars-backward " \t\n")
+			       (and (not (eolp))
+				    (progn
+				      (forward-char -1)
+				      (not (looking-at "{")))
+				    (progn
+				      (forward-word -1)
+				      (not (looking-at "do\\>[^_]")))))
+			      (t t))))
+		       (not (eq ?, c))
+		       (setq op-end t)))))
+	   (setq indent
+		 (cond
+		  ((and
+		    (null op-end)
+		    (not (looking-at (concat "\\<\\(" ruby-block-hanging-re "\\)\\>")))
+		    (eq (ruby-deep-indent-paren-p t) 'space)
+		    (not (bobp)))
+		   (save-excursion
+		     (widen)
+		     (goto-char (or begin parse-start))
+		     (skip-syntax-forward " ")
+		     (current-column)))
+		  ((car (nth 1 state)) indent)
+		  (t
+		   (+ indent ruby-indent-level))))))))
+      indent)))
 
 (defun ruby-electric-brace (arg)
   (interactive "P")
-  (self-insert-command (prefix-numeric-value arg))
-  (ruby-indent-line t))
+  (insert-char last-command-char 1)
+  (ruby-indent-line t)
+  (delete-char -1)
+  (self-insert-command (prefix-numeric-value arg)))
 
-(defun ruby-beginning-of-defun (&optional arg)
+(eval-when-compile
+  (defmacro defun-region-command (func args &rest body)
+    (let ((intr (car body)))
+      (when (featurep 'xemacs)
+	(if (stringp intr) (setq intr (cadr body)))
+	(and (eq (car intr) 'interactive)
+	     (setq intr (cdr intr))
+	     (setcar intr (concat "_" (car intr)))))
+      (cons 'defun (cons func (cons args body))))))
+
+(defun-region-command ruby-beginning-of-defun (&optional arg)
   "Move backward to next beginning-of-defun.
 With argument, do this that many times.
 Returns t unless search stops due to end of buffer."
 	 (beginning-of-line)
 	 t)))
 
-(defun ruby-end-of-defun (&optional arg)
+(defun-region-command ruby-end-of-defun (&optional arg)
   "Move forward to next end of defun.
 An end of a defun is found by moving forward from the beginning of one."
   (interactive "p")
 (defun ruby-move-to-block (n)
   (let (start pos done down)
     (setq start (ruby-calculate-indent))
-    (if (eobp)
-	nil
-      (while (and (not (bobp)) (not (eobp)) (not done))
-	(forward-line n)
+    (setq down (looking-at (concat "\\<\\(" (if (< n 0) ruby-block-end-re ruby-block-beg-re) "\\)\\>")))
+    (while (and (not done) (not (if (< n 0) (bobp) (eobp))))
+      (forward-line n)
+      (cond
+       ((looking-at "^\\s *$"))
+       ((looking-at "^\\s *#"))
+       ((and (> n 0) (looking-at "^=begin\\>"))
+	(re-search-forward "^=end\\>"))
+       ((and (< n 0) (looking-at "^=end\\>"))
+	(re-search-backward "^=begin\\>"))
+       (t
+	(setq pos (current-indentation))
 	(cond
-	 ((looking-at "^$"))
-	 ((looking-at "^\\s *#"))
-	 (t
-	  (setq pos (current-indentation))
-	  (cond
-	   ((< start pos)
-	    (setq down t))
-	   ((and down (= pos start))
-	    (setq done t))
-	   ((> start pos)
-	    (setq done t)))))
-	(if done
-	    (progn
-	      (back-to-indentation)
-	      (if (looking-at ruby-block-mid-re)
-		  (setq done nil)))))))
+	 ((< start pos)
+	  (setq down t))
+	 ((and down (= pos start))
+	  (setq done t))
+	 ((> start pos)
+	  (setq done t)))))
+      (if done
+	  (save-excursion
+	    (back-to-indentation)
+	    (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>"))
+		(setq done nil))))))
   (back-to-indentation))
 
-(defun ruby-beginning-of-block ()
-  "Move backward to next beginning-of-block."
-  (interactive)
-  (ruby-move-to-block -1))
+(defun-region-command ruby-beginning-of-block (&optional arg)
+  "Move backward to next beginning-of-block"
+  (interactive "p")
+  (ruby-move-to-block (- (or arg 1))))
 
-(defun ruby-end-of-block ()
-  "Move forward to next beginning-of-block."
-  (interactive)
-  (ruby-move-to-block 1))
+(defun-region-command ruby-end-of-block (&optional arg)
+  "Move forward to next beginning-of-block"
+  (interactive "p")
+  (ruby-move-to-block (or arg 1)))
+
+(defun-region-command ruby-forward-sexp (&optional cnt)
+  (interactive "p")
+  (if (and (numberp cnt) (< cnt 0))
+      (ruby-backward-sexp (- cnt))
+    (let ((i (or cnt 1)))
+      (condition-case nil
+	  (while (> i 0)
+	    (skip-syntax-forward " ")
+	    (cond ((looking-at "\\?\\(\\\\[CM]-\\)*\\\\?\\S ")
+		   (goto-char (match-end 0)))
+		  ((progn
+		     (skip-chars-forward ",.:;|&^~=!?\\+\\-\\*")
+		     (looking-at "\\s("))
+		   (goto-char (scan-sexps (point) 1)))
+		  ((and (looking-at (concat "\\<\\(" ruby-block-beg-re "\\)\\>"))
+			(not (eq (char-before (point)) ?.))
+			(not (eq (char-before (point)) ?:)))
+		   (ruby-end-of-block)
+		   (forward-word 1))
+		  ((looking-at "\\(\\$\\|@@?\\)?\\sw")
+		   (while (progn
+			    (while (progn (forward-word 1) (looking-at "_")))
+			    (cond ((looking-at "::") (forward-char 2) t)
+				  ((> (skip-chars-forward ".") 0))
+				  ((looking-at "\\?\\|!\\(=[~=>]\\|[^~=]\\)")
+				   (forward-char 1) nil)))))
+		  ((let (state expr)
+		     (while
+			 (progn
+			   (setq expr (or expr (ruby-expr-beg)
+					  (looking-at "%\\sw?\\Sw\\|[\"'`/]")))
+			   (nth 1 (setq state (apply 'ruby-parse-partial nil state))))
+		       (setq expr t)
+		       (skip-chars-forward "<"))
+		     (not expr))))
+	    (setq i (1- i)))
+	((error) (forward-word 1)))
+      i)))
+
+(defun-region-command ruby-backward-sexp (&optional cnt)
+  (interactive "p")
+  (if (and (numberp cnt) (< cnt 0))
+      (ruby-forward-sexp (- cnt))
+    (let ((i (or cnt 1)))
+      (condition-case nil
+	  (while (> i 0)
+	    (skip-chars-backward " \t\n,.:;|&^~=!?\\+\\-\\*")
+	    (forward-char -1)
+	    (cond ((looking-at "\\s)")
+		   (goto-char (scan-sexps (1+ (point)) -1))
+		   (case (char-before)
+		     (?% (forward-char -1))
+		     ('(?q ?Q ?w ?W ?r ?x)
+		      (if (eq (char-before (1- (point))) ?%) (forward-char -2))))
+		   nil)
+		  ((looking-at "\\s\"\\|\\\\\\S_")
+		   (let ((c (char-to-string (char-before (match-end 0)))))
+		     (while (and (search-backward c)
+				 (oddp (skip-chars-backward "\\")))))
+		   nil)
+		  ((looking-at "\\s.\\|\\s\\")
+		   (if (ruby-special-char-p) (forward-char -1)))
+		  ((looking-at "\\s(") nil)
+		  (t
+		   (forward-char 1)
+		   (while (progn (forward-word -1)
+				 (case (char-before)
+				   (?_ t)
+				   (?. (forward-char -1) t)
+				   ((?$ ?@)
+				    (forward-char -1)
+				    (and (eq (char-before) (char-after)) (forward-char -1)))
+				   (?:
+				    (forward-char -1)
+				    (eq (char-before) :)))))
+		   (if (looking-at (concat "\\<\\(" ruby-block-end-re "\\)\\>"))
+		       (ruby-beginning-of-block))
+		   nil))
+	    (setq i (1- i)))
+	((error)))
+      i)))
 
 (defun ruby-reindent-then-newline-and-indent ()
   (interactive "*")
   (ruby-beginning-of-defun)
   (re-search-backward "^\n" (- (point) 1) t))
 
+(defun ruby-indent-exp (&optional shutup-p)
+  "Indent each line in the balanced expression following point syntactically.
+If optional SHUTUP-P is non-nil, no errors are signalled if no
+balanced expression is found."
+  (interactive "*P")
+  (let ((here (point-marker)) start top column (nest t))
+    (set-marker-insertion-type here t)
+    (unwind-protect
+	(progn
+	  (beginning-of-line)
+	  (setq start (point) top (current-indentation))
+	  (while (and (not (eobp))
+		      (progn
+			(setq column (ruby-calculate-indent start))
+			(cond ((> column top)
+			       (setq nest t))
+			      ((and (= column top) nest)
+			       (setq nest nil) t))))
+	    (ruby-indent-to column)
+	    (beginning-of-line 2)))
+      (goto-char here)
+      (set-marker here nil))))
+
+(defun ruby-add-log-current-method ()
+  "Return current method string."
+  (condition-case nil
+      (save-excursion
+	(let ((mlist nil) (indent 0))
+	  ;; get current method (or class/module)
+	  (if (re-search-backward
+	       (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+"
+		       "\\(" 
+		       ;; \\. for class method
+			"\\(" ruby-symbol-re "\\|\\." "\\)" 
+			"+\\)")
+	       nil t)
+	      (progn
+		(setq mlist (list (match-string 2)))
+		(goto-char (match-beginning 1))
+		(setq indent (current-column))
+		(beginning-of-line)))
+	  ;; nest class/module
+	  (while (and (> indent 0)
+		      (re-search-backward
+		       (concat
+			"^[ \t]*\\(class\\|module\\)[ \t]+"
+			"\\([A-Z]" ruby-symbol-re "+\\)")
+		       nil t))
+	    (goto-char (match-beginning 1))
+	    (if (< (current-column) indent)
+		(progn
+		  (setq mlist (cons (match-string 2) mlist))
+		  (setq indent (current-column))
+		  (beginning-of-line))))
+	  ;; generate string
+	  (if (consp mlist)
+	      (mapconcat (function identity) mlist "::")
+	    nil)))))
+
 (cond
  ((featurep 'font-lock)
   (or (boundp 'font-lock-variable-name-face)
 	'(
 	  ;; #{ }, #$hoge, #@foo are not comments
 	  ("\\(#\\)[{$@]" 1 (1 . nil))
-	  ;; the last $' in the string ,'...$' is not variable
-	  ;; the last ?' in the string ,'...?' is not ascii code
-	  ("\\(^\\|[[\\s <+(,=]\\)\\('\\)[^'\n\\\\]*\\(\\\\.[^'\n\\\\]*\\)*[?$]\\('\\)"
-	   (2 (7 . nil))
-	   (4 (7 . nil)))
-	  ;; the last $` in the string ,`...$` is not variable
-	  ;; the last ?` in the string ,`...?` is not ascii code
-	  ("\\(^\\|[[\\s <+(,=]\\)\\(`\\)[^`\n\\\\]*\\(\\\\.[^`\n\\\\]*\\)*[?$]\\(`\\)"
-	   (2 (7 . nil))
-	   (4 (7 . nil)))
-	  ;; the last $" in the string ,"...$" is not variable
-	  ;; the last ?" in the string ,"...?" is not ascii code
-	  ("\\(^\\|[[\\s <+(,=]\\)\\(\"\\)[^\"\n\\\\]*\\(\\\\.[^\"\n\\\\]*\\)*[?$]\\(\"\\)"
+	  ;; the last $', $", $` in the respective string is not variable
+	  ;; the last ?', ?", ?` in the respective string is not ascii code
+	  ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
 	   (2 (7 . nil))
 	   (4 (7 . nil)))
 	  ;; $' $" $` .... are variables
 	  ;; ?' ?" ?` are ascii codes
-	  ("[?$][#\"'`]" 0 (1 . nil))
+	  ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil))
 	  ;; regexps
 	  ("\\(^\\|[=(,~?:;]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
 	   (4 (7 . ?/))
 	   (6 (7 . ?/)))
-	  ;; %Q!...!
-	  ("\\(^\\|[[\\s <+(,=]\\)%[xrqQ]?\\([^a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\2\\)"
-	   (2 (7 . nil))
-	   (4 (7 . nil)))
 	  ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
 	  ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
 
 	    '(lambda ()
 	       (make-local-variable 'font-lock-defaults)
 	       (make-local-variable 'font-lock-keywords)
+	       (make-local-variable 'font-lock-syntax-table)
 	       (make-local-variable 'font-lock-syntactic-keywords)
 	       (setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
 	       (setq font-lock-keywords ruby-font-lock-keywords)
+	       (setq font-lock-syntax-table ruby-font-lock-syntax-table)
 	       (setq font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))))
 
   (defun ruby-font-lock-docs (limit)
 	    t)
 	nil)))
 
+  (defvar ruby-font-lock-syntax-table
+    (let* ((tbl (copy-syntax-table ruby-mode-syntax-table)))
+      (modify-syntax-entry ?_ "w" tbl)
+      tbl))
+
+  (defun ruby-font-lock-here-docs (limit)
+    (if (re-search-forward ruby-here-doc-beg-re limit t)
+	(let (beg)
+	  (beginning-of-line)
+          (forward-line)
+	  (setq beg (point))
+	  (if (re-search-forward (ruby-here-doc-end-match) nil t)
+	      (progn
+		(set-match-data (list beg (point)))
+		t)))))
+
+  (defun ruby-font-lock-maybe-here-docs (limit)
+    (let (beg)
+      (save-excursion
+	(if (re-search-backward ruby-here-doc-beg-re nil t)
+	    (progn
+	      (beginning-of-line)
+              (forward-line)
+	      (setq beg (point)))))
+      (if (and beg
+	       (let ((end-match (ruby-here-doc-end-match)))
+                 (and (not (re-search-backward end-match beg t))
+		      (re-search-forward end-match nil t))))
+	  (progn
+	    (set-match-data (list beg (point)))
+	    t)
+          nil)))
+
   (defvar ruby-font-lock-keywords
     (list
+     ;; functions
+     '("^\\s *def\\s +\\([^( \t\n]+\\)"
+       1 font-lock-function-name-face)
+     ;; keywords
      (cons (concat
-	    "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\("
+	    "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(defined\\?\\|\\("
 	    (mapconcat
 	     'identity
 	     '("alias"
 	       "yield"
 	       )
 	     "\\|")
-	    "\\)\\>\\([^_]\\|$\\)")
+	    "\\)\\>\\)")
 	   2)
      ;; variables
-     '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\b\\([^_]\\|$\\)"
+     '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>"
        2 font-lock-variable-name-face)
      ;; variables
      '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W"
        0 font-lock-comment-face t)
      '(ruby-font-lock-maybe-docs
        0 font-lock-comment-face t)
+     ;; "here" document
+     '(ruby-font-lock-here-docs
+       0 font-lock-string-face t)
+     '(ruby-font-lock-maybe-here-docs
+       0 font-lock-string-face t)
+     `(,ruby-here-doc-beg-re
+       0 font-lock-string-face t)
+     ;; general delimited string
+     '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
+       (2 font-lock-string-face))
      ;; constants
      '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
        2 font-lock-type-face)
-     ;; functions
-     '("^\\s *def\\s +\\([^( ]+\\)"
-       1 font-lock-function-name-face)
      ;; symbols
      '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
        2 font-lock-reference-face)
      ;; expression expansion
      '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)"
-       0 font-lock-variable-name-face t))
-    "Additional expressions to highlight in `ruby-mode'."))
+       0 font-lock-variable-name-face t)
+     ;; warn lower camel case
+     ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)"
+     ;  0 font-lock-warning-face)
+     )
+    "*Additional expressions to highlight in ruby mode."))
 
  ((featurep 'hilit19)
   (hilit-set-mode-patterns
 
 ;; XEmacs addition
 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.rb$" . ruby-mode))
+;;;###autoload(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode))
 
 (provide 'ruby-mode)
 

File ruby-mode.el.upstream

 
 (defconst ruby-block-end-re "end")
 
+(defconst ruby-here-doc-beg-re
+  "<<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
+
+(defun ruby-here-doc-end-match ()
+  (concat "^"
+	  (if (match-string 1) "[ \t]*" nil)
+	  (regexp-quote
+	   (or (match-string 3)
+	       (match-string 4)
+	       (match-string 5)))))
+
 (defconst ruby-delimiter
-  (concat "[?$/%(){}#\"'`.:]\\|\\[\\|\\]\\|\\<\\("
+  (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
 	  ruby-block-beg-re
 	  "\\|" ruby-block-end-re
-	  "\\)\\>\\|^=begin")
+	  "\\)\\>\\|^=begin\\|" ruby-here-doc-beg-re)
   )
 
 (defconst ruby-negative
   (define-key ruby-mode-map "}" 'ruby-electric-brace)
   (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun)
   (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun)
-  (define-key ruby-mode-map "\e\C-b" 'ruby-beginning-of-block)
-  (define-key ruby-mode-map "\e\C-f" 'ruby-end-of-block)
+  (define-key ruby-mode-map "\e\C-b" 'ruby-backward-sexp)
+  (define-key ruby-mode-map "\e\C-f" 'ruby-forward-sexp)
   (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block)
   (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block)
   (define-key ruby-mode-map "\e\C-h" 'ruby-mark-defun)
+  (define-key ruby-mode-map "\e\C-q" 'ruby-indent-exp)
   (define-key ruby-mode-map "\t" 'ruby-indent-command)
   (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end)
   (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent)
   (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table)
   )
 
-(defvar ruby-indent-level 2
-  "*Indentation of ruby statements.")
+(defcustom ruby-indent-tabs-mode nil
+  "*Indentation can insert tabs in ruby mode if this is non-nil."
+  :type 'boolean :group 'ruby)
+
+(defcustom ruby-indent-level 2
+  "*Indentation of ruby statements."
+  :type 'integer :group 'ruby)
+
+(defcustom ruby-comment-column 32
+  "*Indentation column of comments."
+  :type 'integer :group 'ruby)
+
+(defcustom ruby-deep-arglist t
+  "*Deep indent lists in parenthesis when non-nil.
+Also ignores spaces after parenthesis when 'space."
+  :group 'ruby)
+
+(defcustom ruby-deep-indent-paren '(?\( ?\[ ?\] t)
+  "*Deep indent lists in parenthesis when non-nil. t means continuous line.
+Also ignores spaces after parenthesis when 'space."
+  :group 'ruby)
+
+(defcustom ruby-deep-indent-paren-style 'space
+  "Default deep indent style."
+  :options '(t nil space) :group 'ruby)
 
 (eval-when-compile (require 'cl))
+(defun ruby-imenu-create-index-in-block (prefix beg end)
+  (let ((index-alist '()) (case-fold-search nil)
+	name next pos decl sing)
+    (goto-char beg)
+    (while (re-search-forward "^\\s *\\(\\(class\\>\\(\\s *<<\\)?\\|module\\>\\)\\s *\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\>\\s *\\([^\(\n ]+\\)\\)" end t)
+      (setq sing (match-beginning 3))
+      (setq decl (match-string 5))
+      (setq next (match-end 0))
+      (setq name (or (match-string 4) (match-string 6)))
+      (setq pos (match-beginning 0))
+      (cond
+       ((string= "alias" decl)
+	(if prefix (setq name (concat prefix name)))
+	(push (cons name pos) index-alist))
+       ((string= "def" decl)
+	(if prefix
+	    (setq name
+		  (cond
+		   ((string-match "^self\." name)
+		    (concat (substring prefix 0 -1) (substring name 4)))
+		  (t (concat prefix name)))))
+	(push (cons name pos) index-alist)
+	(ruby-accurate-end-of-block end))
+       (t
+	(if (string= "self" name)
+	    (if prefix (setq name (substring prefix 0 -1)))
+	  (if prefix (setq name (concat (substring prefix 0 -1) "::" name)))
+	  (push (cons name pos) index-alist))
+	(ruby-accurate-end-of-block end)
+	(setq beg (point))
+	(setq index-alist
+	      (nconc (ruby-imenu-create-index-in-block
+		      (concat name (if sing "." "#"))
+		      next beg) index-alist))
+	(goto-char beg))))
+    index-alist))
+
 (defun ruby-imenu-create-index ()
-  (let ((index-alist '())
-	class-name class-begin method-name method-begin decl)
-    (goto-char (point-min))
-    (while (re-search-forward "^\\s *\\(class\\|def\\)\\s *\\([^(\n ]+\\)" nil t)
-      (setq decl (buffer-substring (match-beginning 1) (match-end 1)))
-      (cond
-       ((string= "class" decl)
-	(setq class-begin (match-beginning 2))
-	(setq class-name (buffer-substring class-begin (match-end 2)))
-	(push (cons class-name (match-beginning 0)) index-alist)
-	(ruby-mark-defun)
-	(save-restriction
-	  (narrow-to-region (region-beginning) (region-end))
-         (while (re-search-forward "^\\s *def\\s *\\([^(\n ]+\\)" nil 'move)
-	    (setq method-begin (match-beginning 1))
-	    (setq method-name (buffer-substring method-begin (match-end 1)))
-	    (push (cons (concat class-name "#" method-name) (match-beginning 0)) index-alist))))
-       ((string= "def" decl)
-	(setq method-begin (match-beginning 2))
-	(setq method-name (buffer-substring method-begin (match-end 2)))
-	(push (cons method-name (match-beginning 0)) index-alist))))
-    index-alist))
+  (nreverse (ruby-imenu-create-index-in-block nil (point-min) nil)))
+
+(defun ruby-accurate-end-of-block (&optional end)
+  (let (state)
+    (or end (setq end (point-max)))
+    (while (and (setq state (apply 'ruby-parse-partial end state))
+		(>= (nth 2 state) 0) (< (point) end)))))
 
 (defun ruby-mode-variables ()
   (set-syntax-table ruby-mode-syntax-table)
   (make-variable-buffer-local 'comment-end)
   (setq comment-end "")
   (make-variable-buffer-local 'comment-column)
-  (setq comment-column 32)
+  (setq comment-column ruby-comment-column)
   (make-variable-buffer-local 'comment-start-skip)
-  (setq comment-start-skip "\\(^\\|\\s-\\);?#+ *")
+  (setq comment-start-skip "#+ *")
+  (setq indent-tabs-mode ruby-indent-tabs-mode)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq parse-sexp-ignore-comments t)
   (make-local-variable 'paragraph-start)
   (make-local-variable 'imenu-create-index-function)
   (setq imenu-create-index-function 'ruby-imenu-create-index)
 
+  (make-local-variable 'add-log-current-defun-function)
+  (setq add-log-current-defun-function 'ruby-add-log-current-method)
+
   (run-hooks 'ruby-mode-hook))
 
 (defun ruby-current-indentation ()
 	  (indent-to x)
 	  (move-to-column (+ x shift))))))
 
+(defun ruby-special-char-p (&optional pnt)
+  (setq pnt (or pnt (point)))
+  (let ((c (char-before pnt)) (b (and (< (point-min) pnt) (char-before (1- pnt)))))
+    (cond ((or (eq c ??) (eq c ?$)))
+	  ((and (eq c ?:) (or (not b) (eq (char-syntax b) ? ))))
+	  ((eq c ?\\) (eq b ??)))))
+
 (defun ruby-expr-beg (&optional option)
   (save-excursion
     (store-match-data nil)
-    (skip-chars-backward " \t")
-    (cond
-     ((bolp) t)
-     ((looking-at "\\?")
-      (or (bolp) (forward-char -1))
-      (not (looking-at "\\sw")))
-     (t
-      (forward-char -1)
-      (or (looking-at ruby-operator-re)
-	  (looking-at "[\\[({,;]")
-	  (and (not (eq option 'modifier))
-	       (looking-at "[!?]"))
-	  (and (looking-at ruby-symbol-re)
-	       (skip-chars-backward ruby-symbol-chars)
-	       (cond
-		((or (looking-at ruby-block-beg-re)
-		     (looking-at ruby-block-op-re)
-		     (looking-at ruby-block-mid-re))
-		 (goto-char (match-end 0))
-		 (looking-at "\\>"))
-		(t
-		 (and (not (eq option 'expr-arg))
-		      (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))))))))))
+    (let ((space (skip-chars-backward " \t"))
+	  (start (point)))
+      (cond
+       ((bolp) t)
+       ((progn
+	  (forward-char -1)
+	  (and (looking-at "\\?")
+	       (or (eq (char-syntax (char-before (point))) ?w)
+		   (ruby-special-char-p))))
+	nil)
+       ((and (eq option 'heredoc) (< space 0)) t)
+       ((or (looking-at ruby-operator-re)
+	    (looking-at "[\\[({,;]")
+	    (and (looking-at "[!?]")
+		 (or (not (eq option 'modifier))
+		     (bolp)
+		     (save-excursion (forward-char -1) (looking-at "\\Sw$"))))
+	    (and (looking-at ruby-symbol-re)
+		 (skip-chars-backward ruby-symbol-chars)
+		 (cond
+		  ((or (looking-at (concat "\\<\\(" ruby-block-beg-re
+					   "|" ruby-block-op-re
+					   "|" ruby-block-mid-re "\\)\\>")))
+		   (goto-char (match-end 0))
+		   (not (looking-at "\\s_")))
+		  ((eq option 'expr-qstr)
+		   (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]"))
+		  ((eq option 'expr-re)
+		   (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))
+		  (t nil)))))))))
 
 (defun ruby-forward-string (term &optional end no-error expand)
   (let ((n 1) (c (string-to-char term))
       (forward-char -1))
     (cond ((zerop n))
 	  (no-error nil)
-	  (error "unterminated string"))))
+	  ((error "unterminated string")))))
 
-(defun ruby-parse-region (start end)
-  (let ((indent-point end)
-	  (indent 0)
-	  (in-string nil)
-	  (in-paren nil)
-	  (depth 0)
-	  (nest nil)
-	  (pcol nil))
-    (save-excursion
-	(if start
-	    (goto-char start)
-	  (ruby-beginning-of-indent))
-	(save-restriction
-	  (narrow-to-region (point) end)
-	  (while (and (> indent-point (point))
-		      (re-search-forward ruby-delimiter indent-point t))
-	    (or depth (setq depth 0))
-	    (let ((pnt (point)) w re expand)
-	      (goto-char (match-beginning 0))
-	      (cond
-	       ((or (looking-at "\"")	;skip string
-		    (looking-at "`"))
-		(cond
-		 ((and (not (eobp))
-		       (ruby-forward-string (buffer-substring (point) (1+ (point))) indent-point t t))
-		  nil)
-		 (t
-		  (setq in-string (point))
-		  (goto-char indent-point))))
-	       ((looking-at "'")
-		(cond
-		 ((and (not (eobp))
-		       (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" indent-point t))
-		  nil)
-		 (t
-		  (setq in-string (point))
-		  (goto-char indent-point))))
-	       ((looking-at "/")
-		(cond
-		 ((and (not (eobp)) (ruby-expr-beg))
-		  (if (ruby-forward-string "/" indent-point t t)
-		      nil
-		    (setq in-string (point))
-		    (goto-char indent-point)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "%")
-		(cond
-		 ((and (not (eobp)) (ruby-expr-beg 'expr-arg)
-		       (not (looking-at "%="))
-		       (looking-at "%[Qqrxw]?\\(.\\)"))
-		  (goto-char (match-beginning 1))
-		  (setq expand (not (eq (char-before) ?q)))
-		  (setq w (buffer-substring (match-beginning 1)
-					    (match-end 1)))
-		  (cond
-		   ((string= w "[") (setq re "]["))
-		   ((string= w "{") (setq re "}{"))
-		   ((string= w "(") (setq re ")("))
-		   ((string= w "<") (setq re "><"))
-		   ((or (and expand (string= w "\\"))
-			(member w '("*" "." "+" "?" "^" "$")))
-		    (setq w (concat "\\" w))))
-		  (unless (cond (re (ruby-forward-string re indent-point t expand))
-				(expand (ruby-forward-string w indent-point t t))
-				(t (re-search-forward
-				    (if (string= w "\\")
-					"\\\\[^\\]*\\\\"
-				      (concat "[^\\]\\(\\\\\\\\\\)*" w))
-				    indent-point t)))
-		    (setq in-string (point))
-		    (goto-char indent-point)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "\\?")	;skip ?char
-		(cond
-		 ((ruby-expr-beg)
-		  (looking-at "?\\(\\\\C-\\|\\\\M-\\)*.")
-		  (goto-char (match-end 0)))
-		 (t
-		  (goto-char pnt))))
-	       ((looking-at "\\$")	;skip $char
-		(goto-char pnt)
-		(forward-char 1))
-	       ((looking-at "#")	;skip comment
-		(forward-line 1)
-		(goto-char (point))
-		)
-	       ((looking-at "(")
+(defun ruby-deep-indent-paren-p (c)
+  (cond ((listp ruby-deep-indent-paren)
+	 (let ((deep (assoc c ruby-deep-indent-paren)))
+	   (cond (deep
+		  (or (cdr deep) ruby-deep-indent-paren-style))
+		 ((memq c ruby-deep-indent-paren)
+		  ruby-deep-indent-paren-style))))
+	((eq c ruby-deep-indent-paren) ruby-deep-indent-paren-style)
+	((eq c ?\( ) ruby-deep-arglist)))
+
+(defun ruby-parse-partial (&optional end in-string nest depth pcol indent)
+  (or depth (setq depth 0))
+  (or indent (setq indent 0))
+  (when (re-search-forward ruby-delimiter end 'move)
+    (let ((pnt (point)) w re expand)
+      (goto-char (match-beginning 0))
+      (cond
+       ((and (memq (char-before) '(?@ ?$)) (looking-at "\\sw"))
+	(goto-char pnt))
+       ((looking-at "[\"`]")		;skip string
+	(cond
+	 ((and (not (eobp))
+	       (ruby-forward-string (buffer-substring (point) (1+ (point))) end t t))
+	  nil)
+	 (t
+	  (setq in-string (point))
+	  (goto-char end))))
+       ((looking-at "'")
+	(cond
+	 ((and (not (eobp))
+	       (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" end t))
+	  nil)
+	 (t
+	  (setq in-string (point))
+	  (goto-char end))))
+       ((looking-at "/")
+	(cond
+	 ((and (not (eobp)) (ruby-expr-beg 'expr-re))
+	  (if (ruby-forward-string "/" end t t)
+	      nil
+	    (setq in-string (point))
+	    (goto-char end)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "%")
+	(cond
+	 ((and (not (eobp))
+	       (ruby-expr-beg 'expr-qstr)
+	       (not (looking-at "%="))
+	       (looking-at "%[QqrxWw]?\\([^a-zA-Z0-9 \t\n]\\)"))
+	  (goto-char (match-beginning 1))
+	  (setq expand (not (memq (char-before) '(?q ?w))))
+	  (setq w (match-string 1))
+	  (cond
+	   ((string= w "[") (setq re "]["))
+	   ((string= w "{") (setq re "}{"))
+	   ((string= w "(") (setq re ")("))
+	   ((string= w "<") (setq re "><"))
+	   ((and expand (string= w "\\"))
+	    (setq w (concat "\\" w))))
+	  (unless (cond (re (ruby-forward-string re end t expand))
+			(expand (ruby-forward-string w end t t))
+			(t (re-search-forward
+			    (if (string= w "\\")
+				"\\\\[^\\]*\\\\"
+			      (concat "[^\\]\\(\\\\\\\\\\)*" w))
+			    end t)))
+	    (setq in-string (point))
+	    (goto-char end)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "\\?")		;skip ?char
+	(cond
+	 ((and (ruby-expr-beg)
+	       (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?."))
+	  (goto-char (match-end 0)))
+	 (t
+	  (goto-char pnt))))
+       ((looking-at "\\$")		;skip $char
+	(goto-char pnt)
+	(forward-char 1))
+       ((looking-at "#")		;skip comment
+	(forward-line 1)
+	(goto-char (point))
+	)
+       ((looking-at "[\\[{(]")
+	(let ((deep (ruby-deep-indent-paren-p (char-after))))
+	  (if (and deep (or (not (eq (char-after) ?\{)) (ruby-expr-beg)))
+	      (progn
+		(and (eq deep 'space) (looking-at ".\\s +[^# \t\n]")
+		     (setq pnt (1- (match-end 0))))
 		(setq nest (cons (cons (char-after (point)) pnt) nest))
 		(setq pcol (cons (cons pnt depth) pcol))
-		(setq depth 0)
-		(goto-char pnt)
-		)
-	       ((looking-at "[\\[{]")
-		(setq nest (cons (cons (char-after (point)) pnt) nest))
-		(setq depth (1+ depth))
-		(goto-char pnt)
-		)
-	       ((looking-at ")")
-		(setq nest (cdr nest))
-		(setq depth (cdr (car pcol)))
-		(setq pcol (cdr pcol))
-		(goto-char pnt))
-	       ((looking-at "[])}]")
-		(setq nest (cdr nest))
-		(setq depth (1- depth))
-		(goto-char pnt))
-	       ((looking-at ruby-block-end-re)
-		(if (or (and (not (bolp))
-			     (progn
-			       (forward-char -1)
-			       (setq w (char-after (point)))
-			       (or (eq ?_ w)
-				   (eq ?. w))))
-			(progn
-			  (goto-char pnt)
-			  (setq w (char-after (point)))
-			  (or (eq ?_ w)
-			      (eq ?! w)
-			      (eq ?? w))))
-		    nil
-		  (setq nest (cdr nest))
-		  (setq depth (1- depth)))
-		(goto-char pnt))
-	       ((looking-at "def\\s +[^(\n;]*")
-		(if (or (bolp)
-			(progn
-			  (forward-char -1)
-			  (not (eq ?_ (char-after (point))))))
-		    (progn
-		      (setq nest (cons (cons nil pnt) nest))
-		      (setq depth (1+ depth))))
-		(goto-char (match-end 0)))
-	       ((looking-at ruby-block-beg-re)
-		(and
-		 (save-match-data
-                   (or (not (looking-at "do\\>[^_]"))
-                       (save-excursion
-                         (back-to-indentation)
-			 (not (looking-at ruby-non-block-do-re)))))
-		 (or (bolp)
+		(setq depth 0))
+	    (setq nest (cons (cons (char-after (point)) pnt) nest))
+	    (setq depth (1+ depth))))
+	(goto-char pnt)
+	)
+       ((looking-at "[])}]")
+	(if (ruby-deep-indent-paren-p (matching-paren (char-after)))
+	    (setq depth (cdr (car pcol)) pcol (cdr pcol))
+	  (setq depth (1- depth)))
+	(setq nest (cdr nest))
+	(goto-char pnt))
+       ((looking-at (concat "\\<\\(" ruby-block-end-re "\\)\\>"))
+	(if (or (and (not (bolp))
 		     (progn
 		       (forward-char -1)