home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ruby164.zip / rbemx164.zip / ruby / share / misc / ruby-1.6.4 / ruby-mode.el < prev    next >
Lisp/Scheme  |  2001-06-18  |  24KB  |  777 lines

  1. ;;;
  2. ;;;  ruby-mode.el -
  3. ;;;
  4. ;;;  $Author: matz $
  5. ;;;  $Date: 2001/02/08 09:18:02 $
  6. ;;;  created at: Fri Feb  4 14:49:13 JST 1994
  7. ;;;
  8.  
  9. (defconst ruby-mode-revision "$Revision: 1.25.2.1 $")
  10.  
  11. (defconst ruby-mode-version
  12.   (progn
  13.    (string-match "[0-9.]+" ruby-mode-revision)
  14.    (substring ruby-mode-revision (match-beginning 0) (match-end 0))))
  15.  
  16. (defconst ruby-block-beg-re
  17.   "class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do"
  18.   )
  19.  
  20. (defconst ruby-non-block-do-re
  21.   "\\(while\\|until\\|for\\|rescue\\)\\>"
  22.   )
  23.  
  24. (defconst ruby-indent-beg-re
  25.   "\\(\\s *\\(class\\|module\\|def\\)\\)\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin"
  26.     )
  27.  
  28. (defconst ruby-modifier-re
  29.   "if\\|unless\\|while\\|until"
  30.   )
  31.  
  32. (defconst ruby-block-mid-re
  33.   "then\\|else\\|elsif\\|when\\|rescue\\|ensure"
  34.   )
  35.  
  36. (defconst ruby-block-op-re
  37.   "and\\|or\\|not"
  38.   )
  39.  
  40. (defconst ruby-block-hanging-re
  41.   (concat ruby-modifier-re "\\|" ruby-block-op-re)
  42.   )
  43.  
  44. (defconst ruby-block-end-re "end")
  45.  
  46. (defconst ruby-delimiter
  47.   (concat "[?$/%(){}#\"'`.:]\\|\\[\\|\\]\\|\\<\\("
  48.       ruby-block-beg-re
  49.       "\\|" ruby-block-end-re
  50.       "\\)\\>\\|^=begin")
  51.   )
  52.  
  53. (defconst ruby-negative
  54.   (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\>\\|\\("
  55.         ruby-block-end-re "\\)\\>\\|}\\|\\]\\)")
  56.   )
  57.  
  58. (defconst ruby-operator-chars "-,.+*/%&|^~=<>:")
  59. (defconst ruby-operator-re (concat "[" ruby-operator-chars "]"))
  60.  
  61. (defconst ruby-symbol-chars "a-zA-Z0-9_")
  62. (defconst ruby-symbol-re (concat "[" ruby-symbol-chars "]"))
  63.  
  64. (defvar ruby-mode-abbrev-table nil
  65.   "Abbrev table in use in ruby-mode buffers.")
  66.  
  67. (define-abbrev-table 'ruby-mode-abbrev-table ())
  68.  
  69. (defvar ruby-mode-map nil "Keymap used in ruby mode.")
  70.  
  71. (if ruby-mode-map
  72.     nil
  73.   (setq ruby-mode-map (make-sparse-keymap))
  74.   (define-key ruby-mode-map "{" 'ruby-electric-brace)
  75.   (define-key ruby-mode-map "}" 'ruby-electric-brace)
  76.   (define-key ruby-mode-map "\e\C-a" 'ruby-beginning-of-defun)
  77.   (define-key ruby-mode-map "\e\C-e" 'ruby-end-of-defun)
  78.   (define-key ruby-mode-map "\e\C-b" 'ruby-beginning-of-block)
  79.   (define-key ruby-mode-map "\e\C-f" 'ruby-end-of-block)
  80.   (define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block)
  81.   (define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block)
  82.   (define-key ruby-mode-map "\e\C-h" 'ruby-mark-defun)
  83.   (define-key ruby-mode-map "\t" 'ruby-indent-command)
  84.   (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end)
  85.   (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent)
  86.   (define-key ruby-mode-map "\C-m" 'newline))
  87.  
  88. (defvar ruby-mode-syntax-table nil
  89.   "Syntax table in use in ruby-mode buffers.")
  90.  
  91. (if ruby-mode-syntax-table
  92.     ()
  93.   (setq ruby-mode-syntax-table (make-syntax-table))
  94.   (modify-syntax-entry ?\' "\"" ruby-mode-syntax-table)
  95.   (modify-syntax-entry ?\" "\"" ruby-mode-syntax-table)
  96.   (modify-syntax-entry ?\` "\"" ruby-mode-syntax-table)
  97.   (modify-syntax-entry ?# "<" ruby-mode-syntax-table)
  98.   (modify-syntax-entry ?\n ">" ruby-mode-syntax-table)
  99.   (modify-syntax-entry ?\\ "\\" ruby-mode-syntax-table)
  100.   (modify-syntax-entry ?$ "." ruby-mode-syntax-table)
  101.   (modify-syntax-entry ?? "_" ruby-mode-syntax-table)
  102.   (modify-syntax-entry ?_ "_" ruby-mode-syntax-table)
  103.   (modify-syntax-entry ?< "." ruby-mode-syntax-table)
  104.   (modify-syntax-entry ?> "." ruby-mode-syntax-table)
  105.   (modify-syntax-entry ?& "." ruby-mode-syntax-table)
  106.   (modify-syntax-entry ?| "." ruby-mode-syntax-table)
  107.   (modify-syntax-entry ?% "." ruby-mode-syntax-table)
  108.   (modify-syntax-entry ?= "." ruby-mode-syntax-table)
  109.   (modify-syntax-entry ?/ "." ruby-mode-syntax-table)
  110.   (modify-syntax-entry ?+ "." ruby-mode-syntax-table)
  111.   (modify-syntax-entry ?* "." ruby-mode-syntax-table)
  112.   (modify-syntax-entry ?- "." ruby-mode-syntax-table)
  113.   (modify-syntax-entry ?\; "." ruby-mode-syntax-table)
  114.   (modify-syntax-entry ?\( "()" ruby-mode-syntax-table)
  115.   (modify-syntax-entry ?\) ")(" ruby-mode-syntax-table)
  116.   (modify-syntax-entry ?\{ "(}" ruby-mode-syntax-table)
  117.   (modify-syntax-entry ?\} "){" ruby-mode-syntax-table)
  118.   (modify-syntax-entry ?\[ "(]" ruby-mode-syntax-table)
  119.   (modify-syntax-entry ?\] ")[" ruby-mode-syntax-table)
  120.   )
  121.  
  122. (defvar ruby-indent-level 2
  123.   "*Indentation of ruby statements.")
  124.  
  125. (eval-when-compile (require 'cl))
  126. (defun ruby-imenu-create-index ()
  127.   (let ((index-alist '())
  128.     class-name class-begin method-name method-begin decl)
  129.     (goto-char (point-min))
  130.     (while (re-search-forward "^\\s *\\(class\\|def\\)\\s *\\([^(\n ]+\\)" nil t)
  131.       (setq decl (buffer-substring (match-beginning 1) (match-end 1)))
  132.       (cond
  133.        ((string= "class" decl)
  134.     (setq class-begin (match-beginning 2))
  135.     (setq class-name (buffer-substring class-begin (match-end 2)))
  136.     (push (cons class-name (match-beginning 0)) index-alist)
  137.     (ruby-mark-defun)
  138.     (save-restriction
  139.       (narrow-to-region (region-beginning) (region-end))
  140.       (while (re-search-forward "^\\s *def\\s *\\([^(\n ]+\\)" nil t)
  141.         (setq method-begin (match-beginning 1))
  142.         (setq method-name (buffer-substring method-begin (match-end 1)))
  143.         (push (cons (concat class-name "#" method-name) (match-beginning 0)) index-alist))))
  144.        ((string= "def" decl)
  145.     (setq method-begin (match-beginning 2))
  146.     (setq method-name (buffer-substring method-begin (match-end 2)))
  147.     (push (cons method-name (match-beginning 0)) index-alist))))
  148.     index-alist))
  149.  
  150. (defun ruby-mode-variables ()
  151.   (set-syntax-table ruby-mode-syntax-table)
  152.   (setq local-abbrev-table ruby-mode-abbrev-table)
  153.   (make-local-variable 'indent-line-function)
  154.   (setq indent-line-function 'ruby-indent-line)
  155.   (make-local-variable 'require-final-newline)
  156.   (setq require-final-newline t)
  157.   (make-variable-buffer-local 'comment-start)
  158.   (setq comment-start "# ")
  159.   (make-variable-buffer-local 'comment-end)
  160.   (setq comment-end "")
  161.   (make-variable-buffer-local 'comment-column)
  162.   (setq comment-column 32)
  163.   (make-variable-buffer-local 'comment-start-skip)
  164.   (setq comment-start-skip "\\(^\\|\\s-\\);?#+ *")
  165.   (make-local-variable 'parse-sexp-ignore-comments)
  166.   (setq parse-sexp-ignore-comments t)
  167.   (make-local-variable 'paragraph-start)
  168.   (setq paragraph-start (concat "$\\|" page-delimiter))
  169.   (make-local-variable 'paragraph-separate)
  170.   (setq paragraph-separate paragraph-start)
  171.   (make-local-variable 'paragraph-ignore-fill-prefix)
  172.   (setq paragraph-ignore-fill-prefix t))
  173.  
  174. (defun ruby-mode ()
  175.   "Major mode for editing ruby scripts.
  176. \\[ruby-indent-command] properly indents subexpressions of multi-line
  177. class, module, def, if, while, for, do, and case statements, taking
  178. nesting into account.
  179.  
  180. The variable ruby-indent-level controls the amount of indentation.
  181. \\{ruby-mode-map}"
  182.   (interactive)
  183.   (kill-all-local-variables)
  184.   (use-local-map ruby-mode-map)
  185.   (setq mode-name "Ruby")
  186.   (setq major-mode 'ruby-mode)
  187.   (ruby-mode-variables)
  188.  
  189.   (make-local-variable 'imenu-create-index-function)
  190.   (setq imenu-create-index-function 'ruby-imenu-create-index)
  191.  
  192.   (run-hooks 'ruby-mode-hook))
  193.  
  194. (defun ruby-current-indentation ()
  195.   (save-excursion
  196.     (beginning-of-line)
  197.     (back-to-indentation)
  198.     (current-column)))
  199.  
  200. (defun ruby-indent-line (&optional flag)
  201.   "Correct indentation of the current ruby line."
  202.   (ruby-indent-to (ruby-calculate-indent)))
  203.  
  204. (defun ruby-indent-command ()
  205.   (interactive)
  206.   (ruby-indent-line t))
  207.  
  208. (defun ruby-indent-to (x)
  209.   (if x
  210.       (let (shift top beg)
  211.     (and (< x 0) (error "invalid nest"))
  212.     (setq shift (current-column))
  213.     (beginning-of-line)
  214.     (setq beg (point))
  215.     (back-to-indentation)
  216.     (setq top (current-column))
  217.     (skip-chars-backward " \t")
  218.     (if (>= shift top) (setq shift (- shift top))
  219.       (setq shift 0))
  220.     (if (and (bolp)
  221.          (= x top))
  222.         (move-to-column (+ x shift))
  223.       (move-to-column top)
  224.       (delete-region beg (point))
  225.       (beginning-of-line)
  226.       (indent-to x)
  227.       (move-to-column (+ x shift))))))
  228.  
  229. (defun ruby-expr-beg (&optional option)
  230.   (save-excursion
  231.     (store-match-data nil)
  232.     (skip-chars-backward " \t")
  233.     (cond
  234.      ((bolp) t)
  235.      ((looking-at "\\?")
  236.       (or (bolp) (forward-char -1))
  237.       (not (looking-at "\\sw")))
  238.      (t
  239.       (forward-char -1)
  240.       (or (looking-at ruby-operator-re)
  241.       (looking-at "[\\[({,;]")
  242.       (and (not (eq option 'modifier))
  243.            (looking-at "[!?]"))
  244.       (and (looking-at ruby-symbol-re)
  245.            (skip-chars-backward ruby-symbol-chars)
  246.            (cond
  247.         ((or (looking-at ruby-block-beg-re)
  248.              (looking-at ruby-block-op-re)
  249.              (looking-at ruby-block-mid-re))
  250.          (goto-char (match-end 0))
  251.          (looking-at "\\>"))
  252.         (t
  253.          (and (not (eq option 'expr-arg))
  254.               (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))))))))))
  255.  
  256. (defun ruby-parse-region (start end)
  257.   (let ((indent-point end)
  258.       (indent 0)
  259.       (in-string nil)
  260.       (in-paren nil)
  261.       (depth 0)
  262.       (nest nil)
  263.       (pcol nil))
  264.     (save-excursion
  265.     (if start
  266.         (goto-char start)
  267.       (ruby-beginning-of-indent))
  268.     (save-restriction
  269.       (narrow-to-region (point) end)
  270.       (while (and (> indent-point (point))
  271.               (re-search-forward ruby-delimiter indent-point t))
  272.         (or depth (setq depth 0))
  273.         (let ((pnt (point)) w)
  274.           (goto-char (match-beginning 0))
  275.           (cond
  276.            ((or (looking-at "\"")    ;skip string
  277.             (looking-at "'")
  278.             (looking-at "`"))
  279.         (setq w (char-after (point)))
  280.         (cond
  281.          ((and (not (eobp))
  282.                (re-search-forward (format "[^\\]\\(\\\\\\\\\\)*%c" w) indent-point t))
  283.           nil)
  284.          (t
  285.           (setq in-string (point))
  286.           (goto-char indent-point))))
  287.            ((looking-at "/")
  288.         (cond
  289.          ((and (not (eobp)) (ruby-expr-beg))
  290.           (if (re-search-forward "[^\\]\\(\\\\\\\\\\)*/" indent-point t)
  291.               nil
  292.             (setq in-string (point))
  293.             (goto-char indent-point)))
  294.          (t
  295.           (goto-char pnt))))
  296.            ((looking-at "%")
  297.         (cond
  298.          ((and (not (eobp)) (ruby-expr-beg 'expr-arg)
  299.                (not (looking-at "%="))
  300.                (looking-at "%[Qqrxw]?\\(.\\)"))
  301.           (goto-char (match-beginning 1))
  302.           (setq w (buffer-substring (match-beginning 1)
  303.                         (match-end 1)))
  304.           (cond
  305.            ((string= w "[") (setq w "\\]"))
  306.            ((string= w "{") (setq w "}"))
  307.            ((string= w "(") (setq w ")"))
  308.            ((string= w "<") (setq w ">"))
  309.            ((member w '("*" "." "+" "?" "^" "$"))
  310.             (setq w (concat "\\" w))))
  311.           (if (re-search-forward
  312.                (if (string= w "\\")
  313.                "\\\\[^\\]*\\\\"
  314.              (concat "[^\\]\\(\\\\\\\\\\)*" w))
  315.                indent-point t)
  316.               nil
  317.             (setq in-string (point))
  318.             (goto-char indent-point)))
  319.          (t
  320.           (goto-char pnt))))
  321.            ((looking-at "\\?")    ;skip ?char
  322.         (cond
  323.          ((ruby-expr-beg)
  324.           (looking-at "?\\(\\\\C-\\|\\\\M-\\)*.")
  325.           (goto-char (match-end 0)))
  326.          (t
  327.           (goto-char pnt))))
  328.            ((looking-at "\\$")    ;skip $char
  329.         (goto-char pnt)
  330.         (forward-char 1))
  331.            ((looking-at "#")    ;skip comment
  332.         (forward-line 1)
  333.         (goto-char (point))
  334.         )
  335.            ((looking-at "(")
  336.         (setq nest (cons (cons (char-after (point)) pnt) nest))
  337.         (setq pcol (cons (cons pnt depth) pcol))
  338.         (setq depth 0)
  339.         (goto-char pnt)
  340.         )
  341.            ((looking-at "[\\[{]")
  342.         (setq nest (cons (cons (char-after (point)) pnt) nest))
  343.         (setq depth (1+ depth))
  344.         (goto-char pnt)
  345.         )
  346.            ((looking-at ")")
  347.         (setq nest (cdr nest))
  348.         (setq depth (cdr (car pcol)))
  349.         (setq pcol (cdr pcol))
  350.         (goto-char pnt))
  351.            ((looking-at "[])}]")
  352.         (setq nest (cdr nest))
  353.         (setq depth (1- depth))
  354.         (goto-char pnt))
  355.            ((looking-at ruby-block-end-re)
  356.         (if (or (and (not (bolp))
  357.                  (progn
  358.                    (forward-char -1)
  359.                    (setq w (char-after (point)))
  360.                    (or (eq ?_ w)
  361.                    (eq ?. w))))
  362.             (progn
  363.               (goto-char pnt)
  364.               (setq w (char-after (point)))
  365.               (or (eq ?_ w)
  366.                   (eq ?! w)
  367.                   (eq ?? w))))
  368.             nil
  369.           (setq nest (cdr nest))
  370.           (setq depth (1- depth)))
  371.         (goto-char pnt))
  372.            ((looking-at "def\\s +[^(\n;]*")
  373.         (if (or (bolp)
  374.             (progn
  375.               (forward-char -1)
  376.               (not (eq ?_ (char-after (point))))))
  377.             (progn
  378.               (setq nest (cons (cons nil pnt) nest))
  379.               (setq depth (1+ depth))))
  380.         (goto-char (match-end 0)))
  381.            ((looking-at ruby-block-beg-re)
  382.         (and
  383.          (save-match-data
  384.                    (or (not (looking-at "do\\>[^_]"))
  385.                        (save-excursion
  386.                          (back-to-indentation)
  387.              (not (looking-at ruby-non-block-do-re)))))
  388.          (or (bolp)
  389.              (progn
  390.                (forward-char -1)
  391.                (setq w (char-after (point)))
  392.                (not (or (eq ?_ w)
  393.                 (eq ?. w)))))
  394.          (goto-char pnt)
  395.          (setq w (char-after (point)))
  396.          (not (eq ?_ w))
  397.          (not (eq ?! w))
  398.          (not (eq ?? w))
  399.          (skip-chars-forward " \t")
  400.          (goto-char (match-beginning 0))
  401.          (or (not (looking-at ruby-modifier-re))
  402.              (ruby-expr-beg 'modifier))
  403.          (goto-char pnt)
  404.          (setq nest (cons (cons nil pnt) nest))
  405.          (setq depth (1+ depth)))
  406.         (goto-char pnt))
  407.            ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*\\)?")
  408.         (goto-char (match-end 0)))
  409.            ((or (looking-at "\\.")
  410.             (looking-at "\\.\\.\\.?")
  411.             (looking-at "\\.[0-9]+")
  412.             (looking-at "\\.[a-zA-Z_0-9]+"))
  413.         (goto-char (match-end 0)))
  414.            ((looking-at "^=begin")
  415.         (if (re-search-forward "^=end" indent-point t)
  416.             (forward-line 1)
  417.           (setq in-string (match-end 0))
  418.           (goto-char indent-point)))
  419.            (t
  420.         (error (format "bad string %s"
  421.                    (buffer-substring (point) pnt)
  422.                    )))))))
  423.     (list in-string (car nest) depth (car (car pcol))))))
  424.  
  425. (defun ruby-indent-size (pos nest)
  426.   (+ pos (* (if nest nest 1) ruby-indent-level)))
  427.  
  428. (defun ruby-calculate-indent (&optional parse-start)
  429.   (save-excursion
  430.     (beginning-of-line)
  431.     (let ((indent-point (point))
  432.         (case-fold-search nil)
  433.         state bol eol
  434.         (indent 0))
  435.     (if parse-start
  436.         (goto-char parse-start)
  437.       (ruby-beginning-of-indent)
  438.       (setq parse-start (point)))
  439.     (back-to-indentation)
  440.     (setq indent (current-column))
  441.     (setq state (ruby-parse-region parse-start indent-point))
  442.     (cond
  443.      ((nth 0 state)            ; within string
  444.       (setq indent nil))        ;  do nothing
  445.      ((car (nth 1 state))        ; in paren
  446.       (goto-char (cdr (nth 1 state)))
  447.       (if (eq (car (nth 1 state)) ?\( )
  448.           (let ((column (current-column))
  449.             (s (ruby-parse-region (point) indent-point)))
  450.         (cond
  451.          ((and (nth 2 s) (> (nth 2 s) 0))
  452.           (goto-char (cdr (nth 1 s)))
  453.           (forward-word -1)
  454.           (setq indent (ruby-indent-size (current-column) (nth 2 state))))
  455.          (t 
  456.           (setq indent (current-column)))))
  457.         (cond
  458.          ((nth 3 state)
  459.           (goto-char (nth 3 state))
  460.           (setq indent (ruby-indent-size (current-column) (nth 2 state))))
  461.          (t
  462.           (goto-char parse-start)
  463.           (back-to-indentation)
  464.           (setq indent (ruby-indent-size (current-column) (nth 2 state)))))
  465.         ))      
  466.      ((and (nth 2 state)(> (nth 2 state) 0)) ; in nest
  467.       (if (null (cdr (nth 1 state)))
  468.           (error "invalid nest"))
  469.       (goto-char (cdr (nth 1 state)))
  470.       (forward-word -1)        ; skip back a keyword
  471.       (cond
  472.        ((looking-at "do\\>[^_]")    ; iter block is a special case
  473.         (cond
  474.          ((nth 3 state)
  475.           (goto-char (nth 3 state))
  476.           (setq indent (ruby-indent-size (current-column) (nth 2 state))))
  477.          (t
  478.           (goto-char parse-start)
  479.           (back-to-indentation)
  480.           (setq indent (ruby-indent-size (current-column) (nth 2 state))))))
  481.        (t
  482.         (setq indent (+ (current-column) ruby-indent-level)))))
  483.  
  484.      ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest
  485.       (setq indent (ruby-indent-size (current-column) (nth 2 state)))))
  486.  
  487.     (cond
  488.      (indent
  489.       (goto-char indent-point)
  490.       (end-of-line)
  491.       (setq eol (point))
  492.       (beginning-of-line)
  493.       (cond 
  494.        ((re-search-forward ruby-negative eol t)
  495.         (and (not (eq ?_ (char-after (match-end 0))))
  496.          (setq indent (- indent ruby-indent-level))))
  497.        ;;operator terminated lines
  498.        ((and
  499.          (save-excursion
  500.            (beginning-of-line)
  501.            (not (bobp)))
  502.          (or (null (car (nth 1 state))) ;not in parens
  503.          (and (eq (car (nth 1 state)) ?\{)
  504.               (save-excursion    ;except non-block braces
  505.             (goto-char (cdr (nth 1 state)))
  506.             (or (bobp) (forward-char -1))
  507.             (not (ruby-expr-beg))))))
  508.         ;; goto beginning of non-empty no-comment line
  509.         (let (end done)
  510.           (while (not done)
  511.         (skip-chars-backward " \t\n")
  512.         (setq end (point))
  513.         (beginning-of-line)
  514.         (if (re-search-forward "^\\s *#" end t)
  515.             (beginning-of-line)
  516.           (setq done t))))
  517.         (setq bol (point))
  518.         (end-of-line)
  519.         (skip-chars-backward " \t")
  520.         (let ((pos (point)))
  521.           (and 
  522.            (re-search-backward "#" (save-excursion
  523.                      (beginning-of-line)
  524.                      (point)) t)
  525.            (skip-chars-backward " \t")
  526.            (setq state (ruby-parse-region parse-start (point)))
  527.            (nth 0 state)
  528.            (goto-char pos)))
  529.         (or (bobp) (forward-char -1))
  530.         (and
  531.          (or (and (looking-at ruby-symbol-re)
  532.               (skip-chars-backward ruby-symbol-chars)
  533.               (looking-at ruby-block-hanging-re)
  534.               (not (eq (point) (nth 3 state)))
  535.               (save-excursion
  536.             (goto-char (match-end 0))
  537.             (not (looking-at "[a-z_]"))))
  538.          (and (looking-at ruby-operator-re)
  539.               (not (eq (char-after (1- (point))) ??))
  540.               (not (eq (char-after (1- (point))) ?$))
  541.               (or (not (eq ?/ (char-after (point))))
  542.               (null (nth 0 (ruby-parse-region parse-start (point)))))
  543.               (or (not (eq ?| (char-after (point))))
  544.               (save-excursion
  545.                 (or (eolp) (forward-char -1))
  546.                 (cond
  547.                  ((search-backward "|" nil t)
  548.                   (skip-chars-backward " \t\n")
  549.                   (and (not (eolp))
  550.                    (progn
  551.                      (forward-char -1)
  552.                      (not (looking-at "{")))
  553.                    (progn
  554.                      (forward-word -1)
  555.                      (not (looking-at "do\\>[^_]")))))
  556.                  (t t))))))
  557.          (setq indent (+ indent ruby-indent-level)))))))
  558.     indent)))
  559.  
  560. (defun ruby-electric-brace (arg)
  561.   (interactive "P")
  562.   (self-insert-command (prefix-numeric-value arg))
  563.   (ruby-indent-line t))
  564.  
  565. (defun ruby-beginning-of-defun (&optional arg)
  566.   "Move backward to next beginning-of-defun.
  567. With argument, do this that many times.
  568. Returns t unless search stops due to end of buffer."
  569.   (interactive "p")
  570.   (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\b")
  571.                nil 'move (or arg 1))
  572.        (progn (beginning-of-line) t)))
  573.  
  574. (defun ruby-beginning-of-indent ()
  575.   (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\b")
  576.                nil 'move)
  577.        (progn
  578.      (beginning-of-line)
  579.      t)))
  580.  
  581. (defun ruby-end-of-defun (&optional arg)
  582.   "Move forward to next end of defun.
  583. An end of a defun is found by moving forward from the beginning of one."
  584.   (interactive "p")
  585.   (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)")
  586.               nil 'move (or arg 1))
  587.        (progn (beginning-of-line) t))
  588.   (forward-line 1))
  589.  
  590. (defun ruby-move-to-block (n)
  591.   (let (start pos done down)
  592.     (setq start (ruby-calculate-indent))
  593.     (if (eobp)
  594.     nil
  595.       (while (and (not (bobp)) (not (eobp)) (not done))
  596.     (forward-line n)
  597.     (cond
  598.      ((looking-at "^$"))
  599.      ((looking-at "^\\s *#"))
  600.      (t
  601.       (setq pos (current-indentation))
  602.       (cond
  603.        ((< start pos)
  604.         (setq down t))
  605.        ((and down (= pos start))
  606.         (setq done t))
  607.        ((> start pos)
  608.         (setq done t)))))
  609.     (if done
  610.         (progn
  611.           (back-to-indentation)
  612.           (if (looking-at ruby-block-mid-re)
  613.           (setq done nil)))))))
  614.   (back-to-indentation))
  615.  
  616. (defun ruby-beginning-of-block ()
  617.   "Move backward to next beginning-of-block"
  618.   (interactive)
  619.   (ruby-move-to-block -1))
  620.  
  621. (defun ruby-end-of-block ()
  622.   "Move forward to next beginning-of-block"
  623.   (interactive)
  624.   (ruby-move-to-block 1))
  625.  
  626. (defun ruby-reindent-then-newline-and-indent ()
  627.   (interactive "*")
  628.   (newline)
  629.   (save-excursion
  630.     (end-of-line 0)
  631.     (indent-according-to-mode)
  632.     (delete-region (point) (progn (skip-chars-backward " \t") (point))))
  633.   (indent-according-to-mode))
  634.  
  635. (fset 'ruby-encomment-region (symbol-function 'comment-region))
  636.  
  637. (defun ruby-decomment-region (beg end)
  638.   (interactive "r")
  639.   (save-excursion
  640.     (goto-char beg)
  641.     (while (re-search-forward "^\\([ \t]*\\)#" end t)
  642.       (replace-match "\\1" nil nil)
  643.       (save-excursion
  644.     (ruby-indent-line)))))
  645.  
  646. (defun ruby-insert-end ()
  647.   (interactive)
  648.   (insert "end")
  649.   (ruby-indent-line t)
  650.   (end-of-line))
  651.  
  652. (defun ruby-mark-defun ()
  653.   "Put mark at end of this Ruby function, point at beginning."
  654.   (interactive)
  655.   (push-mark (point))
  656.   (ruby-end-of-defun)
  657.   (push-mark (point) nil t)
  658.   (ruby-beginning-of-defun)
  659.   (re-search-backward "^\n" (- (point) 1) t))
  660.  
  661. (cond
  662.  ((featurep 'font-lock)
  663.   (or (boundp 'font-lock-variable-name-face)
  664.       (setq font-lock-variable-name-face font-lock-type-face))
  665.  
  666.  
  667.   (add-hook 'ruby-mode-hook
  668.         '(lambda ()
  669.            (make-local-variable 'font-lock-syntactic-keywords)
  670.            (setq font-lock-syntactic-keywords
  671.              '(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil))
  672.                ("\\(#\\)[{$@]" 1 (1 . nil))
  673.                ("\\(/\\)\\([^/\n]\\|\\\\/\\)*\\(/\\)"
  674.             (1 (7 . ?'))
  675.             (3 (7 . ?')))))
  676.            (make-local-variable 'font-lock-defaults)
  677.            (setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
  678.            (setq font-lock-keywords ruby-font-lock-keywords)))
  679.  
  680.   (defun ruby-font-lock-docs (limit)
  681.     (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t)
  682.     (let (beg)
  683.       (beginning-of-line)
  684.       (setq beg (point))
  685.       (forward-line 1)
  686.       (if (re-search-forward "^=end\\(\\s \\|$\\)" limit t)
  687.           (progn
  688.         (set-match-data (list beg (point)))
  689.         t)))))
  690.  
  691.   (defvar ruby-font-lock-keywords
  692.     (list
  693.      (cons (concat
  694.         "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\("
  695.         (mapconcat
  696.          'identity
  697.          '("alias"
  698.            "and"
  699.            "begin"
  700.            "break"
  701.            "case"
  702.            "catch"
  703.            "class"
  704.            "def"
  705.            "do"
  706.            "elsif"
  707.            "else"
  708.            "fail"
  709.            "ensure"
  710.            "for"
  711.            "end"
  712.            "if"
  713.            "in"
  714.            "module"
  715.            "next"
  716.            "not"
  717.            "or"
  718.            "raise"
  719.            "redo"
  720.            "rescue"
  721.            "retry"
  722.            "return"
  723.            "then"
  724.            "throw"
  725.            "super"
  726.            "unless"
  727.            "undef"
  728.            "until"
  729.            "when"
  730.            "while"
  731.            "yield"
  732.            )
  733.          "\\|")
  734.         "\\)\\>\\([^_]\\|$\\)")
  735.        2)
  736.      ;; variables
  737.      '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\b\\([^_]\\|$\\)"
  738.        2 font-lock-variable-name-face)
  739.      ;; variables
  740.      '("[$@].\\(\\w\\|_\\)*"
  741.        0 font-lock-variable-name-face)
  742.      ;; embedded document
  743.      '(ruby-font-lock-docs
  744.        0 font-lock-comment-face t)
  745.      ;; constants
  746.      '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
  747.        2 font-lock-type-face)
  748.      ;; functions
  749.      '("^\\s *def\\s +\\([^( ]+\\)"
  750.        1 font-lock-function-name-face)
  751.      ;; symbols
  752.      '("\\(^\\|[^:]\\)\\(:\\([-+/%&|^~`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b\\)\\)\\)"
  753.        2 font-lock-reference-face))
  754.     "*Additional expressions to highlight in ruby mode."))
  755.  
  756.  ((featurep 'hilit19)
  757.   (hilit-set-mode-patterns
  758.    'ruby-mode
  759.    '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string)
  760.      ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string)
  761.      ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string)
  762.      ("^\\s *#.*$" nil comment)
  763.      ("[^$@?\\]\\(#[^$@{\n].*$\\)" 1 comment)
  764.      ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string)
  765.      ("^\\s *\\(require\\|load\\).*$" nil include)
  766.      ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl)
  767.      ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun)
  768.      ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\|yield\\)\\>\\([^_]\\|$\\)" 1 defun)
  769.      ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|catch\\|throw\\|self\\|nil\\)\\>\\([^_]\\|$\\)" 1 keyword)
  770.      ("\\$\\(.\\|\\sw+\\)" nil type)
  771.      ("[$@].[a-zA-Z_0-9]*" nil struct)
  772.      ("^__END__" nil label))))
  773.  )
  774.  
  775.  
  776. (provide 'ruby-mode)
  777.