5 ;;; created at: Fri Feb 4 14:49:13 JST 1994
8 (defconst ruby-mode-revision
"$Revision$"
9 "Ruby mode revision string.")
11 (defconst ruby-mode-version
13 (string-match "[0-9.]+" ruby-mode-revision
)
14 (substring ruby-mode-revision
(match-beginning 0) (match-end 0)))
15 "Ruby mode version number.")
17 (defconst ruby-block-beg-re
18 "class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do"
19 "Regexp to match the beginning of blocks in ruby-mode.")
21 (defconst ruby-non-block-do-re
22 "\\(while\\|until\\|for\\|rescue\\)\\>[^_]"
25 (defconst ruby-indent-beg-re
26 "\\(\\s *\\(class\\|module\\|def\\)\\)\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin"
27 "Regexp to match where the indentation gets deeper.")
29 (defconst ruby-modifier-beg-re
30 "if\\|unless\\|while\\|until"
31 "Regexp to match modifiers same as the beginning of blocks.")
33 (defconst ruby-modifier-re
34 (concat ruby-modifier-beg-re
"\\|rescue")
35 "Regexp to match modifiers.")
37 (defconst ruby-block-mid-re
38 "then\\|else\\|elsif\\|when\\|rescue\\|ensure"
39 "Regexp to match where the indentation gets shallower in middle of block statements.")
41 (defconst ruby-block-op-re
45 (defconst ruby-block-hanging-re
46 (concat ruby-modifier-beg-re
"\\|" ruby-block-op-re
)
49 (defconst ruby-block-end-re
"\\<end\\>")
51 (defconst ruby-here-doc-beg-re
52 "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
54 (defconst ruby-here-doc-end-re
55 "^\\([ \t]+\\)?\\(.*\\)\\(.\\)$")
57 (defun ruby-here-doc-end-match ()
59 (if (match-string 2) "[ \t]*" nil
)
65 (defun ruby-here-doc-beg-match ()
66 (let ((contents (regexp-quote (concat (match-string 2) (match-string 3)))))
68 (let ((match (match-string 1)))
69 (if (and match
(> (length match
) 0))
70 (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)" (match-string 1) "\\)"
71 contents
"\\(\\1\\|\\2\\)")
72 (concat "-?\\([\"']\\|\\)" contents
"\\1"))))))
74 (defconst ruby-delimiter
75 (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
77 "\\)\\>\\|" ruby-block-end-re
78 "\\|^=begin\\|" ruby-here-doc-beg-re
)
81 (defconst ruby-negative
82 (concat "^[ \t]*\\(\\(" ruby-block-mid-re
"\\)\\>\\|"
83 ruby-block-end-re
"\\|}\\|\\]\\)")
84 "Regexp to match where the indentation gets shallower.")
86 (defconst ruby-operator-chars
"-,.+*/%&|^~=<>:")
87 (defconst ruby-operator-re
(concat "[" ruby-operator-chars
"]"))
89 (defconst ruby-symbol-chars
"a-zA-Z0-9_")
90 (defconst ruby-symbol-re
(concat "[" ruby-symbol-chars
"]"))
92 (defvar ruby-mode-abbrev-table nil
93 "Abbrev table in use in ruby-mode buffers.")
95 (define-abbrev-table 'ruby-mode-abbrev-table
())
97 (defvar ruby-mode-map nil
"Keymap used in ruby mode.")
101 (setq ruby-mode-map
(make-sparse-keymap))
102 (define-key ruby-mode-map
"{" 'ruby-electric-brace
)
103 (define-key ruby-mode-map
"}" 'ruby-electric-brace
)
104 (define-key ruby-mode-map
"\e\C-a" 'ruby-beginning-of-defun
)
105 (define-key ruby-mode-map
"\e\C-e" 'ruby-end-of-defun
)
106 (define-key ruby-mode-map
"\e\C-b" 'ruby-backward-sexp
)
107 (define-key ruby-mode-map
"\e\C-f" 'ruby-forward-sexp
)
108 (define-key ruby-mode-map
"\e\C-p" 'ruby-beginning-of-block
)
109 (define-key ruby-mode-map
"\e\C-n" 'ruby-end-of-block
)
110 (define-key ruby-mode-map
"\e\C-h" 'ruby-mark-defun
)
111 (define-key ruby-mode-map
"\e\C-q" 'ruby-indent-exp
)
112 (define-key ruby-mode-map
"\t" 'ruby-indent-command
)
113 (define-key ruby-mode-map
"\C-c\C-e" 'ruby-insert-end
)
114 (define-key ruby-mode-map
"\C-j" 'ruby-reindent-then-newline-and-indent
)
115 (define-key ruby-mode-map
"\C-m" 'newline
))
117 (defvar ruby-mode-syntax-table nil
118 "Syntax table in use in ruby-mode buffers.")
120 (if ruby-mode-syntax-table
122 (setq ruby-mode-syntax-table
(make-syntax-table))
123 (modify-syntax-entry ?
\' "\"" ruby-mode-syntax-table
)
124 (modify-syntax-entry ?
\" "\"" ruby-mode-syntax-table
)
125 (modify-syntax-entry ?\
` "\"" ruby-mode-syntax-table
)
126 (modify-syntax-entry ?
# "<" ruby-mode-syntax-table
)
127 (modify-syntax-entry ?
\n ">" ruby-mode-syntax-table
)
128 (modify-syntax-entry ?
\\ "\\" ruby-mode-syntax-table
)
129 (modify-syntax-entry ?$
"." ruby-mode-syntax-table
)
130 (modify-syntax-entry ??
"_" ruby-mode-syntax-table
)
131 (modify-syntax-entry ?_
"_" ruby-mode-syntax-table
)
132 (modify-syntax-entry ?
< "." ruby-mode-syntax-table
)
133 (modify-syntax-entry ?
> "." ruby-mode-syntax-table
)
134 (modify-syntax-entry ?
& "." ruby-mode-syntax-table
)
135 (modify-syntax-entry ?|
"." ruby-mode-syntax-table
)
136 (modify-syntax-entry ?%
"." ruby-mode-syntax-table
)
137 (modify-syntax-entry ?
= "." ruby-mode-syntax-table
)
138 (modify-syntax-entry ?
/ "." ruby-mode-syntax-table
)
139 (modify-syntax-entry ?
+ "." ruby-mode-syntax-table
)
140 (modify-syntax-entry ?
* "." ruby-mode-syntax-table
)
141 (modify-syntax-entry ?-
"." ruby-mode-syntax-table
)
142 (modify-syntax-entry ?\
; "." ruby-mode-syntax-table)
143 (modify-syntax-entry ?\
( "()" ruby-mode-syntax-table
)
144 (modify-syntax-entry ?\
) ")(" ruby-mode-syntax-table
)
145 (modify-syntax-entry ?\
{ "(}" ruby-mode-syntax-table
)
146 (modify-syntax-entry ?\
} "){" ruby-mode-syntax-table
)
147 (modify-syntax-entry ?\
[ "(]" ruby-mode-syntax-table
)
148 (modify-syntax-entry ?\
] ")[" ruby-mode-syntax-table
)
151 (defcustom ruby-indent-tabs-mode nil
152 "*Indentation can insert tabs in ruby mode if this is non-nil."
153 :type
'boolean
:group
'ruby
)
155 (defcustom ruby-indent-level
2
156 "*Indentation of ruby statements."
157 :type
'integer
:group
'ruby
)
159 (defcustom ruby-comment-column
32
160 "*Indentation column of comments."
161 :type
'integer
:group
'ruby
)
163 (defcustom ruby-deep-arglist t
164 "*Deep indent lists in parenthesis when non-nil.
165 Also ignores spaces after parenthesis when 'space."
168 (defcustom ruby-deep-indent-paren
'(?\
( ?\
[ ?\
] t
)
169 "*Deep indent lists in parenthesis when non-nil. t means continuous line.
170 Also ignores spaces after parenthesis when 'space."
173 (defcustom ruby-deep-indent-paren-style
'space
174 "Default deep indent style."
175 :options
'(t nil space
) :group
'ruby
)
177 (defcustom ruby-encoding-map
'((shift_jis . cp932
) (shift-jis . cp932
))
178 "Alist to map encoding name from emacs to ruby."
181 (defcustom ruby-use-encoding-map t
182 "*Use `ruby-encoding-map' to set encoding magic comment if this is non-nil."
183 :type
'boolean
:group
'ruby
)
185 (eval-when-compile (require 'cl
))
186 (defun ruby-imenu-create-index-in-block (prefix beg end
)
187 (let ((index-alist '())
188 name next pos decl sing
)
190 (while (re-search-forward "^\\s *\\(\\(class\\s +\\|\\(class\\s *<<\\s *\\)\\|module\\s +\\)\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\s +\\([^\(\n ]+\\)\\)" end t
)
191 (setq sing
(match-beginning 3))
192 (setq decl
(match-string 5))
193 (setq next
(match-end 0))
194 (setq name
(or (match-string 4) (match-string 6)))
195 (setq pos
(match-beginning 0))
197 ((string= "alias" decl
)
198 (if prefix
(setq name
(concat prefix name
)))
199 (push (cons name pos
) index-alist
))
200 ((string= "def" decl
)
204 ((string-match "^self\." name
)
205 (concat (substring prefix
0 -
1) (substring name
4)))
206 (t (concat prefix name
)))))
207 (push (cons name pos
) index-alist
)
208 (ruby-accurate-end-of-block end
))
210 (if (string= "self" name
)
211 (if prefix
(setq name
(substring prefix
0 -
1)))
212 (if prefix
(setq name
(concat (substring prefix
0 -
1) "::" name
)))
213 (push (cons name pos
) index-alist
))
214 (ruby-accurate-end-of-block end
)
217 (nconc (ruby-imenu-create-index-in-block
218 (concat name
(if sing
"." "#"))
219 next beg
) index-alist
))
223 (defun ruby-imenu-create-index ()
224 (nreverse (ruby-imenu-create-index-in-block nil
(point-min) nil
)))
226 (defun ruby-accurate-end-of-block (&optional end
)
228 (or end
(setq end
(point-max)))
229 (while (and (setq state
(apply 'ruby-parse-partial end state
))
230 (>= (nth 2 state
) 0) (< (point) end
)))))
232 (defun ruby-mode-variables ()
233 (set-syntax-table ruby-mode-syntax-table
)
234 (setq local-abbrev-table ruby-mode-abbrev-table
)
235 (setq case-fold-search nil
)
236 (make-local-variable 'indent-line-function
)
237 (setq indent-line-function
'ruby-indent-line
)
238 (make-local-variable 'require-final-newline
)
239 (setq require-final-newline t
)
240 (make-variable-buffer-local 'comment-start
)
241 (setq comment-start
"# ")
242 (make-variable-buffer-local 'comment-end
)
243 (setq comment-end
"")
244 (make-variable-buffer-local 'comment-column
)
245 (setq comment-column ruby-comment-column
)
246 (make-variable-buffer-local 'comment-start-skip
)
247 (setq comment-start-skip
"#+ *")
248 (setq indent-tabs-mode ruby-indent-tabs-mode
)
249 (make-local-variable 'parse-sexp-ignore-comments
)
250 (setq parse-sexp-ignore-comments t
)
251 (make-local-variable 'parse-sexp-lookup-properties
)
252 (setq parse-sexp-lookup-properties t
)
253 (make-local-variable 'paragraph-start
)
254 (setq paragraph-start
(concat "$\\|" page-delimiter
))
255 (make-local-variable 'paragraph-separate
)
256 (setq paragraph-separate paragraph-start
)
257 (make-local-variable 'paragraph-ignore-fill-prefix
)
258 (setq paragraph-ignore-fill-prefix t
))
260 (defun ruby-mode-set-encoding ()
263 (goto-char (point-min))
264 (when (re-search-forward "[^\0-\177]" nil t
)
265 (goto-char (point-min))
267 (or coding-system-for-write
268 buffer-file-coding-system
)))
271 (or (coding-system-get coding-system
'mime-charset
)
272 (coding-system-change-eol-conversion coding-system nil
))))
276 (or (and ruby-use-encoding-map
277 (cdr (assq coding-system ruby-encoding-map
)))
280 (if (looking-at "^#![^\n]*ruby") (beginning-of-line 2))
281 (cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)\\s *\\(;\\|-\*-\\)")
282 (unless (string= (match-string 2) coding-system
)
283 (goto-char (match-beginning 2))
284 (delete-region (point) (match-end 2))
285 (and (looking-at "-\*-")
286 (let ((n (skip-chars-backward " ")))
287 (cond ((= n
0) (insert " ") (backward-char))
288 ((= n -
1) (insert " "))
290 (insert coding-system
)))
291 ((looking-at "\\s *#.*coding\\s *[:=]"))
292 (t (insert "# -*- coding: " coding-system
" -*-\n"))
297 "Major mode for editing ruby scripts.
298 \\[ruby-indent-command] properly indents subexpressions of multi-line
299 class, module, def, if, while, for, do, and case statements, taking
300 nesting into account.
302 The variable ruby-indent-level controls the amount of indentation.
305 (kill-all-local-variables)
306 (use-local-map ruby-mode-map
)
307 (setq mode-name
"Ruby")
308 (setq major-mode
'ruby-mode
)
309 (ruby-mode-variables)
311 (make-local-variable 'imenu-create-index-function
)
312 (setq imenu-create-index-function
'ruby-imenu-create-index
)
314 (make-local-variable 'add-log-current-defun-function
)
315 (setq add-log-current-defun-function
'ruby-add-log-current-method
)
318 (cond ((boundp 'before-save-hook
)
319 (make-local-variable 'before-save-hook
)
321 ((boundp 'write-contents-functions
) 'write-contents-functions
)
322 ((boundp 'write-contents-hooks
) 'write-contents-hooks
))
323 'ruby-mode-set-encoding
)
325 (set (make-local-variable 'font-lock-defaults
) '((ruby-font-lock-keywords) nil nil
))
326 (set (make-local-variable 'font-lock-keywords
) ruby-font-lock-keywords
)
327 (set (make-local-variable 'font-lock-syntax-table
) ruby-font-lock-syntax-table
)
328 (set (make-local-variable 'font-lock-syntactic-keywords
) ruby-font-lock-syntactic-keywords
)
330 (if (fboundp 'run-mode-hooks
)
331 (run-mode-hooks 'ruby-mode-hook
)
332 (run-hooks 'ruby-mode-hook
)))
334 (defun ruby-current-indentation ()
337 (back-to-indentation)
340 (defun ruby-indent-line (&optional flag
)
341 "Correct indentation of the current ruby line."
342 (ruby-indent-to (ruby-calculate-indent)))
344 (defun ruby-indent-command ()
346 (ruby-indent-line t
))
348 (defun ruby-indent-to (x)
351 (and (< x
0) (error "invalid nest"))
352 (setq shift
(current-column))
355 (back-to-indentation)
356 (setq top
(current-column))
357 (skip-chars-backward " \t")
358 (if (>= shift top
) (setq shift
(- shift top
))
362 (move-to-column (+ x shift
))
364 (delete-region beg
(point))
367 (move-to-column (+ x shift
))))))
369 (defun ruby-special-char-p (&optional pnt
)
370 (setq pnt
(or pnt
(point)))
371 (let ((c (char-before pnt
)) (b (and (< (point-min) pnt
) (char-before (1- pnt
)))))
372 (cond ((or (eq c ??
) (eq c ?$
)))
373 ((and (eq c ?
:) (or (not b
) (eq (char-syntax b
) ?
))))
374 ((eq c ?
\\) (eq b ??
)))))
376 (defun ruby-expr-beg (&optional option
)
378 (store-match-data nil
)
379 (let ((space (skip-chars-backward " \t"))
385 (and (looking-at "\\?")
386 (or (eq (char-syntax (char-before (point))) ?w
)
387 (ruby-special-char-p))))
389 ((and (eq option
'heredoc
) (< space
0)) t
)
390 ((or (looking-at ruby-operator-re
)
391 (looking-at "[\\[({,;]")
392 (and (looking-at "[!?]")
393 (or (not (eq option
'modifier
))
395 (save-excursion (forward-char -
1) (looking-at "\\Sw$"))))
396 (and (looking-at ruby-symbol-re
)
397 (skip-chars-backward ruby-symbol-chars
)
399 ((or (looking-at (concat "\\<\\(" ruby-block-beg-re
401 "|" ruby-block-mid-re
"\\)\\>")))
402 (goto-char (match-end 0))
403 (not (looking-at "\\s_")))
404 ((eq option
'expr-qstr
)
405 (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]"))
406 ((eq option
'expr-re
)
407 (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))
410 (defun ruby-forward-string (term &optional end no-error expand
)
411 (let ((n 1) (c (string-to-char term
))
413 (concat "[^\\]\\(\\\\\\\\\\)*\\([" term
"]\\|\\(#{\\)\\)")
414 (concat "[^\\]\\(\\\\\\\\\\)*[" term
"]"))))
415 (while (and (re-search-forward re end no-error
)
416 (if (match-beginning 3)
417 (ruby-forward-string "}{" end no-error nil
)
418 (> (setq n
(if (eq (char-before (point)) c
)
423 ((error "unterminated string")))))
425 (defun ruby-deep-indent-paren-p (c)
426 (cond ((listp ruby-deep-indent-paren
)
427 (let ((deep (assoc c ruby-deep-indent-paren
)))
429 (or (cdr deep
) ruby-deep-indent-paren-style
))
430 ((memq c ruby-deep-indent-paren
)
431 ruby-deep-indent-paren-style
))))
432 ((eq c ruby-deep-indent-paren
) ruby-deep-indent-paren-style
)
433 ((eq c ?\
( ) ruby-deep-arglist
)))
435 (defun ruby-parse-partial (&optional end in-string nest depth pcol indent
)
436 (or depth
(setq depth
0))
437 (or indent
(setq indent
0))
438 (when (re-search-forward ruby-delimiter end
'move
)
439 (let ((pnt (point)) w re expand
)
440 (goto-char (match-beginning 0))
442 ((and (memq (char-before) '(?
@ ?$
)) (looking-at "\\sw"))
444 ((looking-at "[\"`]") ;skip string
447 (ruby-forward-string (buffer-substring (point) (1+ (point))) end t t
))
450 (setq in-string
(point))
455 (re-search-forward "[^\\]\\(\\\\\\\\\\)*'" end t
))
458 (setq in-string
(point))
464 ((and (not (eobp)) (ruby-expr-beg 'expr-re
))
465 (if (ruby-forward-string "/" end t t
)
467 (setq in-string
(point))
474 (ruby-expr-beg 'expr-qstr
)
475 (not (looking-at "%="))
476 (looking-at "%[QqrxWw]?\\([^a-zA-Z0-9 \t\n]\\)"))
477 (goto-char (match-beginning 1))
478 (setq expand
(not (memq (char-before) '(?q ?w
))))
479 (setq w
(match-string 1))
481 ((string= w
"[") (setq re
"]["))
482 ((string= w
"{") (setq re
"}{"))
483 ((string= w
"(") (setq re
")("))
484 ((string= w
"<") (setq re
"><"))
485 ((and expand
(string= w
"\\"))
486 (setq w
(concat "\\" w
))))
487 (unless (cond (re (ruby-forward-string re end t expand
))
488 (expand (ruby-forward-string w end t t
))
489 (t (re-search-forward
492 (concat "[^\\]\\(\\\\\\\\\\)*" w
))
494 (setq in-string
(point))
498 ((looking-at "\\?") ;skip ?char
500 ((and (ruby-expr-beg)
501 (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?."))
502 (goto-char (match-end 0)))
505 ((looking-at "\\$") ;skip $char
508 ((looking-at "#") ;skip comment
512 ((looking-at "[\\[{(]")
513 (let ((deep (ruby-deep-indent-paren-p (char-after))))
514 (if (and deep
(or (not (eq (char-after) ?\
{)) (ruby-expr-beg)))
516 (and (eq deep
'space
) (looking-at ".\\s +[^# \t\n]")
517 (setq pnt
(1- (match-end 0))))
518 (setq nest
(cons (cons (char-after (point)) pnt
) nest
))
519 (setq pcol
(cons (cons pnt depth
) pcol
))
521 (setq nest
(cons (cons (char-after (point)) pnt
) nest
))
522 (setq depth
(1+ depth
))))
525 ((looking-at "[])}]")
526 (if (ruby-deep-indent-paren-p (matching-paren (char-after)))
527 (setq depth
(cdr (car pcol
)) pcol
(cdr pcol
))
528 (setq depth
(1- depth
)))
529 (setq nest
(cdr nest
))
531 ((looking-at ruby-block-end-re
)
532 (if (or (and (not (bolp))
535 (setq w
(char-after (point)))
540 (setq w
(char-after (point)))
545 (setq nest
(cdr nest
))
546 (setq depth
(1- depth
)))
548 ((looking-at "def\\s +[^(\n;]*")
552 (not (eq ?_
(char-after (point))))))
554 (setq nest
(cons (cons nil pnt
) nest
))
555 (setq depth
(1+ depth
))))
556 (goto-char (match-end 0)))
557 ((looking-at (concat "\\<\\(" ruby-block-beg-re
"\\)\\>"))
560 (or (not (looking-at "do\\>[^_]"))
562 (back-to-indentation)
563 (not (looking-at ruby-non-block-do-re
)))))
567 (setq w
(char-after (point)))
571 (setq w
(char-after (point)))
575 (skip-chars-forward " \t")
576 (goto-char (match-beginning 0))
577 (or (not (looking-at ruby-modifier-re
))
578 (ruby-expr-beg 'modifier
))
580 (setq nest
(cons (cons nil pnt
) nest
))
581 (setq depth
(1+ depth
)))
583 ((looking-at ":\\(['\"]\\)")
584 (goto-char (match-beginning 1))
585 (ruby-forward-string (buffer-substring (match-beginning 1) (match-end 1)) end
))
586 ((looking-at ":\\([-,.+*/%&|^~<>]=?\\|===?\\|<=>\\)")
587 (goto-char (match-end 0)))
588 ((looking-at ":\\([a-zA-Z_][a-zA-Z_0-9]*[!?=]?\\)?")
589 (goto-char (match-end 0)))
590 ((or (looking-at "\\.\\.\\.?")
591 (looking-at "\\.[0-9]+")
592 (looking-at "\\.[a-zA-Z_0-9]+")
594 (goto-char (match-end 0)))
595 ((looking-at "^=begin")
596 (if (re-search-forward "^=end" end t
)
598 (setq in-string
(match-end 0))
602 ((and (ruby-expr-beg 'heredoc
)
603 (looking-at "<<\\(-\\)?\\(\\([\"'`]\\)\\([^\n]+?\\)\\3\\|\\(?:\\sw\\|\\s_\\)+\\)"))
604 (setq re
(regexp-quote (or (match-string 4) (match-string 2))))
605 (if (match-beginning 1) (setq re
(concat "\\s *" re
)))
606 (let* ((id-end (goto-char (match-end 0)))
607 (line-end-position (save-excursion (end-of-line) (point)))
608 (state (list in-string nest depth pcol indent
)))
609 ;; parse the rest of the line
610 (while (and (> line-end-position
(point))
611 (setq state
(apply 'ruby-parse-partial
612 line-end-position state
))))
613 (setq in-string
(car state
)
617 indent
(nth 4 state
))
618 ;; skip heredoc section
619 (if (re-search-forward (concat "^" re
"$") end
'move
)
621 (setq in-string id-end
)
625 ((looking-at "^__END__$")
627 ((looking-at ruby-here-doc-beg-re
)
628 (if (re-search-forward (ruby-here-doc-end-match)
631 (setq in-string
(match-end 0))
632 (goto-char indent-point
)))
634 (error (format "bad string %s"
635 (buffer-substring (point) pnt
)
637 (list in-string nest depth pcol
))
639 (defun ruby-parse-region (start end
)
644 (ruby-beginning-of-indent))
646 (narrow-to-region (point) end
)
647 (while (and (> end
(point))
648 (setq state
(apply 'ruby-parse-partial end state
))))))
649 (list (nth 0 state
) ; in-string
650 (car (nth 1 state
)) ; nest
651 (nth 2 state
) ; depth
652 (car (car (nth 3 state
))) ; pcol
653 ;(car (nth 5 state)) ; indent
656 (defun ruby-indent-size (pos nest
)
657 (+ pos
(* (or nest
1) ruby-indent-level
)))
659 (defun ruby-calculate-indent (&optional parse-start
)
662 (let ((indent-point (point))
663 state bol eol begin op-end
664 (paren (progn (skip-syntax-forward " ")
665 (and (char-after) (matching-paren (char-after)))))
668 (goto-char parse-start
)
669 (ruby-beginning-of-indent)
670 (setq parse-start
(point)))
671 (back-to-indentation)
672 (setq indent
(current-column))
673 (setq state
(ruby-parse-region parse-start indent-point
))
675 ((nth 0 state
) ; within string
676 (setq indent nil
)) ; do nothing
677 ((car (nth 1 state
)) ; in paren
678 (goto-char (setq begin
(cdr (nth 1 state
))))
679 (let ((deep (ruby-deep-indent-paren-p (car (nth 1 state
)))))
681 (cond ((and (eq deep t
) (eq (car (nth 1 state
)) paren
))
682 (skip-syntax-backward " ")
683 (setq indent
(1- (current-column))))
684 ((let ((s (ruby-parse-region (point) indent-point
)))
685 (and (nth 2 s
) (> (nth 2 s
) 0)
686 (or (goto-char (cdr (nth 1 s
))) t
)))
688 (setq indent
(ruby-indent-size (current-column) (nth 2 state
))))
690 (setq indent
(current-column))
691 (cond ((eq deep
'space
))
692 (paren (setq indent
(1- indent
)))
693 (t (setq indent
(ruby-indent-size (1- indent
) 1))))))
694 (if (nth 3 state
) (goto-char (nth 3 state
))
695 (goto-char parse-start
) (back-to-indentation))
696 (setq indent
(ruby-indent-size (current-column) (nth 2 state
))))
697 (and (eq (car (nth 1 state
)) paren
)
698 (ruby-deep-indent-paren-p (matching-paren paren
))
699 (search-backward (char-to-string paren
))
700 (setq indent
(current-column)))))
701 ((and (nth 2 state
) (> (nth 2 state
) 0)) ; in nest
702 (if (null (cdr (nth 1 state
)))
703 (error "invalid nest"))
704 (goto-char (cdr (nth 1 state
)))
705 (forward-word -
1) ; skip back a keyword
708 ((looking-at "do\\>[^_]") ; iter block is a special case
709 (if (nth 3 state
) (goto-char (nth 3 state
))
710 (goto-char parse-start
) (back-to-indentation))
711 (setq indent
(ruby-indent-size (current-column) (nth 2 state
))))
713 (setq indent
(+ (current-column) ruby-indent-level
)))))
715 ((and (nth 2 state
) (< (nth 2 state
) 0)) ; in negative nest
716 (setq indent
(ruby-indent-size (current-column) (nth 2 state
)))))
718 (goto-char indent-point
)
723 ((and (not (ruby-deep-indent-paren-p paren
))
724 (re-search-forward ruby-negative eol t
))
725 (and (not (eq ?_
(char-after (match-end 0))))
726 (setq indent
(- indent ruby-indent-level
))))
731 (or (ruby-deep-indent-paren-p t
)
732 (null (car (nth 1 state
)))))
733 ;; goto beginning of non-empty no-comment line
736 (skip-chars-backward " \t\n")
739 (if (re-search-forward "^\\s *#" end t
)
744 ;; skip the comment at the end
745 (skip-chars-backward " \t")
746 (let (end (pos (point)))
748 (while (and (re-search-forward "#" pos t
)
749 (setq end
(1- (point)))
750 (or (ruby-special-char-p end
)
751 (and (setq state
(ruby-parse-region parse-start end
))
754 (goto-char (or end pos
))
755 (skip-chars-backward " \t")
756 (setq begin
(if (and end
(nth 0 state
)) pos
(cdr (nth 1 state
))))
757 (setq state
(ruby-parse-region parse-start
(point))))
758 (or (bobp) (forward-char -
1))
760 (or (and (looking-at ruby-symbol-re
)
761 (skip-chars-backward ruby-symbol-chars
)
762 (looking-at (concat "\\<\\(" ruby-block-hanging-re
"\\)\\>"))
763 (not (eq (point) (nth 3 state
)))
765 (goto-char (match-end 0))
766 (not (looking-at "[a-z_]"))))
767 (and (looking-at ruby-operator-re
)
768 (not (ruby-special-char-p))
769 ;; operator at the end of line
770 (let ((c (char-after (point))))
775 ;; (skip-chars-forward " \t")
776 ;; (not (or (eolp) (looking-at "#")
777 ;; (and (eq (car (nth 1 state)) ?{)
778 ;; (looking-at "|"))))))
780 (null (nth 0 (ruby-parse-region (or begin parse-start
) (point)))))
781 (or (not (eq ?|
(char-after (point))))
783 (or (eolp) (forward-char -
1))
785 ((search-backward "|" nil t
)
786 (skip-chars-backward " \t\n")
790 (not (looking-at "{")))
793 (not (looking-at "do\\>[^_]")))))
801 (not (looking-at (concat "\\<\\(" ruby-block-hanging-re
"\\)\\>")))
802 (eq (ruby-deep-indent-paren-p t
) 'space
)
805 (goto-char (or begin parse-start
))
806 (skip-syntax-forward " ")
808 ((car (nth 1 state
)) indent
)
810 (+ indent ruby-indent-level
))))))))
811 (goto-char indent-point
)
813 (skip-syntax-forward " ")
814 (if (looking-at "\\.[^.]")
815 (+ indent ruby-indent-level
)
818 (defun ruby-electric-brace (arg)
820 (insert-char last-command-char
1)
823 (self-insert-command (prefix-numeric-value arg
)))
826 (defmacro defun-region-command
(func args
&rest body
)
827 (let ((intr (car body
)))
828 (when (featurep 'xemacs
)
829 (if (stringp intr
) (setq intr
(cadr body
)))
830 (and (eq (car intr
) 'interactive
)
831 (setq intr
(cdr intr
))
832 (setcar intr
(concat "_" (car intr
)))))
833 (cons 'defun
(cons func
(cons args body
))))))
835 (defun-region-command ruby-beginning-of-defun
(&optional arg
)
836 "Move backward to next beginning-of-defun.
837 With argument, do this that many times.
838 Returns t unless search stops due to end of buffer."
840 (and (re-search-backward (concat "^\\(" ruby-block-beg-re
"\\)\\b")
841 nil
'move
(or arg
1))
842 (progn (beginning-of-line) t
)))
844 (defun ruby-beginning-of-indent ()
845 (and (re-search-backward (concat "^\\(" ruby-indent-beg-re
"\\)\\b")
851 (defun-region-command ruby-end-of-defun
(&optional arg
)
852 "Move forward to next end of defun.
853 An end of a defun is found by moving forward from the beginning of one."
855 (and (re-search-forward (concat "^\\(" ruby-block-end-re
"\\)\\($\\|\\b[^_]\\)")
856 nil
'move
(or arg
1))
857 (progn (beginning-of-line) t
))
860 (defun ruby-move-to-block (n)
861 (let (start pos done down
)
862 (setq start
(ruby-calculate-indent))
863 (setq down
(looking-at (if (< n
0) ruby-block-end-re
864 (concat "\\<\\(" ruby-block-beg-re
"\\)\\>"))))
865 (while (and (not done
) (not (if (< n
0) (bobp) (eobp))))
868 ((looking-at "^\\s *$"))
869 ((looking-at "^\\s *#"))
870 ((and (> n
0) (looking-at "^=begin\\>"))
871 (re-search-forward "^=end\\>"))
872 ((and (< n
0) (looking-at "^=end\\>"))
873 (re-search-backward "^=begin\\>"))
875 (setq pos
(current-indentation))
879 ((and down
(= pos start
))
885 (back-to-indentation)
886 (if (looking-at (concat "\\<\\(" ruby-block-mid-re
"\\)\\>"))
888 (back-to-indentation))
890 (defun-region-command ruby-beginning-of-block
(&optional arg
)
891 "Move backward to next beginning-of-block"
893 (ruby-move-to-block (- (or arg
1))))
895 (defun-region-command ruby-end-of-block
(&optional arg
)
896 "Move forward to next beginning-of-block"
898 (ruby-move-to-block (or arg
1)))
900 (defun-region-command ruby-forward-sexp
(&optional cnt
)
902 (if (and (numberp cnt
) (< cnt
0))
903 (ruby-backward-sexp (- cnt
))
904 (let ((i (or cnt
1)))
907 (skip-syntax-forward " ")
908 (cond ((looking-at "\\?\\(\\\\[CM]-\\)*\\\\?\\S ")
909 (goto-char (match-end 0)))
911 (skip-chars-forward ",.:;|&^~=!?\\+\\-\\*")
913 (goto-char (scan-sexps (point) 1)))
914 ((and (looking-at (concat "\\<\\(" ruby-block-beg-re
"\\)\\>"))
915 (not (eq (char-before (point)) ?.
))
916 (not (eq (char-before (point)) ?
:)))
919 ((looking-at "\\(\\$\\|@@?\\)?\\sw")
921 (while (progn (forward-word 1) (looking-at "_")))
922 (cond ((looking-at "::") (forward-char 2) t
)
923 ((> (skip-chars-forward ".") 0))
924 ((looking-at "\\?\\|!\\(=[~=>]\\|[^~=]\\)")
925 (forward-char 1) nil
)))))
929 (setq expr
(or expr
(ruby-expr-beg)
930 (looking-at "%\\sw?\\Sw\\|[\"'`/]")))
931 (nth 1 (setq state
(apply 'ruby-parse-partial nil state
))))
933 (skip-chars-forward "<"))
936 ((error) (forward-word 1)))
939 (defun-region-command ruby-backward-sexp
(&optional cnt
)
941 (if (and (numberp cnt
) (< cnt
0))
942 (ruby-forward-sexp (- cnt
))
943 (let ((i (or cnt
1)))
946 (skip-chars-backward " \t\n,.:;|&^~=!?\\+\\-\\*")
948 (cond ((looking-at "\\s)")
949 (goto-char (scan-sexps (1+ (point)) -
1))
951 (?%
(forward-char -
1))
952 ('(?q ?Q ?w ?W ?r ?x
)
953 (if (eq (char-before (1- (point))) ?%
) (forward-char -
2))))
955 ((looking-at "\\s\"\\|\\\\\\S_")
956 (let ((c (char-to-string (char-before (match-end 0)))))
957 (while (and (search-backward c
)
958 (oddp (skip-chars-backward "\\")))))
960 ((looking-at "\\s.\\|\\s\\")
961 (if (ruby-special-char-p) (forward-char -
1)))
962 ((looking-at "\\s(") nil
)
965 (while (progn (forward-word -
1)
968 (?.
(forward-char -
1) t
)
971 (and (eq (char-before) (char-after)) (forward-char -
1)))
974 (eq (char-before) :)))))
975 (if (looking-at ruby-block-end-re
)
976 (ruby-beginning-of-block))
982 (defun ruby-reindent-then-newline-and-indent ()
987 (indent-according-to-mode)
988 (delete-region (point) (progn (skip-chars-backward " \t") (point))))
989 (indent-according-to-mode))
991 (fset 'ruby-encomment-region
(symbol-function 'comment-region
))
993 (defun ruby-decomment-region (beg end
)
997 (while (re-search-forward "^\\([ \t]*\\)#" end t
)
998 (replace-match "\\1" nil nil
)
1000 (ruby-indent-line)))))
1002 (defun ruby-insert-end ()
1005 (ruby-indent-line t
)
1008 (defun ruby-mark-defun ()
1009 "Put mark at end of this Ruby function, point at beginning."
1013 (push-mark (point) nil t
)
1014 (ruby-beginning-of-defun)
1015 (re-search-backward "^\n" (- (point) 1) t
))
1017 (defun ruby-indent-exp (&optional shutup-p
)
1018 "Indent each line in the balanced expression following point syntactically.
1019 If optional SHUTUP-P is non-nil, no errors are signalled if no
1020 balanced expression is found."
1022 (let ((here (point-marker)) start top column
(nest t
))
1023 (set-marker-insertion-type here t
)
1027 (setq start
(point) top
(current-indentation))
1028 (while (and (not (eobp))
1030 (setq column
(ruby-calculate-indent start
))
1031 (cond ((> column top
)
1033 ((and (= column top
) nest
)
1034 (setq nest nil
) t
))))
1035 (ruby-indent-to column
)
1036 (beginning-of-line 2)))
1038 (set-marker here nil
))))
1040 (defun ruby-add-log-current-method ()
1041 "Return current method string."
1044 (let (mname mlist
(indent 0))
1045 ;; get current method (or class/module)
1046 (if (re-search-backward
1047 (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+"
1049 ;; \\. and :: for class method
1050 "\\([A-Za-z_]" ruby-symbol-re
"*\\|\\.\\|::" "\\)"
1054 (setq mname
(match-string 2))
1055 (unless (string-equal "def" (match-string 1))
1056 (setq mlist
(list mname
) mname nil
))
1057 (goto-char (match-beginning 1))
1058 (setq indent
(current-column))
1059 (beginning-of-line)))
1060 ;; nest class/module
1061 (while (and (> indent
0)
1064 "^[ \t]*\\(class\\|module\\)[ \t]+"
1065 "\\([A-Z]" ruby-symbol-re
"*\\)")
1067 (goto-char (match-beginning 1))
1068 (if (< (current-column) indent
)
1070 (setq mlist
(cons (match-string 2) mlist
))
1071 (setq indent
(current-column))
1072 (beginning-of-line))))
1074 (let ((mn (split-string mname
"\\.\\|::")))
1078 ((string-equal "" (car mn
))
1079 (setq mn
(cdr mn
) mlist nil
))
1080 ((string-equal "self" (car mn
))
1082 ((let ((ml (nreverse mlist
)))
1084 (if (string-equal (car ml
) (car mn
))
1085 (setq mlist
(nreverse (cdr ml
)) ml nil
))
1086 (or (setq ml
(cdr ml
)) (nreverse mlist
))))))
1088 (setcdr (last mlist
) mn
)
1090 (setq mn
(last mn
2))
1091 (setq mname
(concat "." (cadr mn
)))
1093 (setq mname
(concat "#" mname
)))))
1096 (setq mlist
(mapconcat (function identity
) mlist
"::")))
1098 (if mlist
(concat mlist mname
) mname
)
1102 ((featurep 'font-lock
)
1103 (or (boundp 'font-lock-variable-name-face
)
1104 (setq font-lock-variable-name-face font-lock-type-face
))
1106 (setq ruby-font-lock-syntactic-keywords
1108 ;; #{ }, #$hoge, #@foo are not comments
1109 ("\\(#\\)[{$@]" 1 (1 . nil
))
1110 ;; the last $', $", $` in the respective string is not variable
1111 ;; the last ?', ?", ?` in the respective string is not ascii code
1112 ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
1115 ;; $' $" $` .... are variables
1116 ;; ?' ?" ?` are ascii codes
1117 ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil
))
1119 ("\\(^\\|[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
1122 ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil
))
1123 ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil
))
1124 (,(concat ruby-here-doc-beg-re
".*\\(\n\\)")
1125 ,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re
))
1126 (ruby-here-doc-beg-syntax))
1127 (,ruby-here-doc-end-re
3 (ruby-here-doc-end-syntax))))
1129 (defun ruby-in-non-here-doc-string-p ()
1130 (let ((syntax (syntax-ppss)))
1132 ;; In a string *without* a generic delimiter
1133 ;; If it's generic, it's a heredoc and we don't care
1134 ;; See `parse-partial-sexp'
1135 (numberp (nth 3 syntax
)))))
1137 (defun ruby-in-here-doc-p ()
1139 (let ((old-point (point)))
1142 (while (re-search-backward ruby-here-doc-beg-re nil t
)
1143 (if (not (or (syntax-ppss-context (syntax-ppss))
1144 (ruby-here-doc-find-end old-point
)))
1145 (throw 'found-beg t
)))))))
1147 (defun ruby-here-doc-find-end (&optional limit
)
1148 "Expects the point to be on a line with one or more heredoc
1149 openers. Returns the buffer position at which all heredocs on the
1150 line are terminated, or nil if they aren't terminated before the
1151 buffer position `limit' or the end of the buffer."
1155 (let ((eol (save-excursion (end-of-line) (point)))
1156 ;; Fake match data such that (match-end 0) is at eol
1157 (end-match-data (progn (looking-at ".*$") (match-data)))
1158 beg-match-data end-re
)
1159 (while (re-search-forward ruby-here-doc-beg-re eol t
)
1160 (setq beg-match-data
(match-data))
1161 (setq end-re
(ruby-here-doc-end-match))
1163 (set-match-data end-match-data
)
1164 (goto-char (match-end 0))
1165 (unless (re-search-forward end-re limit t
) (throw 'done nil
))
1166 (setq end-match-data
(match-data))
1168 (set-match-data beg-match-data
)
1169 (goto-char (match-end 0)))
1170 (set-match-data end-match-data
)
1171 (goto-char (match-end 0))
1174 (defun ruby-here-doc-beg-syntax ()
1176 (goto-char (match-beginning 0))
1177 (unless (or (ruby-in-non-here-doc-string-p)
1178 (ruby-in-here-doc-p))
1179 (string-to-syntax "|"))))
1181 (defun ruby-here-doc-end-syntax ()
1183 (goto-char (match-end 0))
1184 (let ((old-point (point))
1185 (beg-exists (re-search-backward (ruby-here-doc-beg-match) nil t
))
1186 (eol (save-excursion (end-of-line) (point))))
1187 (if (and beg-exists
; If there is a heredoc that matches this line...
1188 (null (syntax-ppss-context (syntax-ppss))) ; And that's not inside a heredoc/string/comment...
1189 (progn (goto-char (match-end 0)) ; And it's the last heredoc on its line...
1190 (not (re-search-forward ruby-here-doc-beg-re eol t
)))
1191 (eq old-point
(ruby-here-doc-find-end old-point
))) ; And it ends at this point...
1192 (string-to-syntax "|")))))
1194 (if (featurep 'xemacs
)
1195 (put 'ruby-mode
'font-lock-defaults
1196 '((ruby-font-lock-keywords)
1199 (font-lock-syntactic-keywords
1200 . ruby-font-lock-syntactic-keywords
))))
1202 (defun ruby-font-lock-docs (limit)
1203 (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t
)
1208 (if (re-search-forward "^=end\\(\\s \\|$\\)" limit t
)
1210 (set-match-data (list beg
(point)))
1213 (defun ruby-font-lock-maybe-docs (limit)
1216 (if (and (re-search-backward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t
)
1217 (string= (match-string 1) "begin"))
1220 (setq beg
(point)))))
1221 (if (and beg
(and (re-search-forward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t
)
1222 (string= (match-string 1) "end")))
1224 (set-match-data (list beg
(point)))
1228 (defvar ruby-font-lock-syntax-table
1229 (let* ((tbl (copy-syntax-table ruby-mode-syntax-table
)))
1230 (modify-syntax-entry ?_
"w" tbl
)
1233 (defconst ruby-font-lock-keywords
1236 '("^\\s *def\\s +\\([^( \t\n]+\\)"
1237 1 font-lock-function-name-face
)
1240 "\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(defined\\?\\|\\("
1282 ;; here-doc beginnings
1283 (list ruby-here-doc-beg-re
0 'font-lock-string-face
)
1285 '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>"
1286 2 font-lock-variable-name-face
)
1288 '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W"
1289 1 font-lock-variable-name-face
)
1290 '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+"
1291 0 font-lock-variable-name-face
)
1292 ;; embedded document
1293 '(ruby-font-lock-docs
1294 0 font-lock-comment-face t
)
1295 '(ruby-font-lock-maybe-docs
1296 0 font-lock-comment-face t
)
1297 ;; general delimited string
1298 '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
1299 (2 font-lock-string-face
))
1301 '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
1302 2 font-lock-type-face
)
1304 '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
1305 2 font-lock-reference-face
)
1306 ;; expression expansion
1307 '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)"
1308 0 font-lock-variable-name-face t
)
1309 ;; warn lower camel case
1310 ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)"
1311 ; 0 font-lock-warning-face)
1313 "*Additional expressions to highlight in ruby mode."))
1315 ((featurep 'hilit19
)
1316 (hilit-set-mode-patterns
1318 '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string
)
1319 ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string
)
1320 ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string
)
1321 ("^\\s *#.*$" nil comment
)
1322 ("[^$@?\\]\\(#[^$@{\n].*$\\)" 1 comment
)
1323 ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string
)
1324 ("^\\s *\\(require\\|load\\).*$" nil include
)
1325 ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl
)
1326 ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun
)
1327 ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\|yield\\)\\>\\([^_]\\|$\\)" 1 defun
)
1328 ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|catch\\|throw\\|self\\|nil\\)\\>\\([^_]\\|$\\)" 1 keyword
)
1329 ("\\$\\(.\\|\\sw+\\)" nil type
)
1330 ("[$@].[a-zA-Z_0-9]*" nil struct
)
1331 ("^__END__" nil label
))))
1335 (provide 'ruby-mode
)