aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/ruby-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/ruby-mode.el')
-rw-r--r--lisp/progmodes/ruby-mode.el173
1 files changed, 89 insertions, 84 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 457c7fee36c..77ec8084ea2 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -64,8 +64,8 @@
64 "Regexp to match keywords that nest without blocks.") 64 "Regexp to match keywords that nest without blocks.")
65 65
66(defconst ruby-indent-beg-re 66(defconst ruby-indent-beg-re
67 (concat "\\(\\s *" (regexp-opt '("class" "module" "def") t) "\\)\\|" 67 (concat "^\\s *" (regexp-opt '("class" "module" "def" "if" "unless" "case"
68 (regexp-opt '("if" "unless" "case" "while" "until" "for" "begin"))) 68 "while" "until" "for" "begin")) "\\_>")
69 "Regexp to match where the indentation gets deeper.") 69 "Regexp to match where the indentation gets deeper.")
70 70
71(defconst ruby-modifier-beg-keywords 71(defconst ruby-modifier-beg-keywords
@@ -98,6 +98,10 @@
98 98
99(defconst ruby-block-end-re "\\_<end\\_>") 99(defconst ruby-block-end-re "\\_<end\\_>")
100 100
101(defconst ruby-defun-beg-re
102 '"\\(def\\|class\\|module\\)"
103 "Regexp to match the beginning of a defun, in the general sense.")
104
101(eval-and-compile 105(eval-and-compile
102 (defconst ruby-here-doc-beg-re 106 (defconst ruby-here-doc-beg-re
103 "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" 107 "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)"
@@ -138,18 +142,11 @@ This should only be called after matching against `ruby-here-doc-beg-re'."
138 142
139(defvar ruby-mode-map 143(defvar ruby-mode-map
140 (let ((map (make-sparse-keymap))) 144 (let ((map (make-sparse-keymap)))
141 (define-key map "{" 'ruby-electric-brace)
142 (define-key map "}" 'ruby-electric-brace)
143 (define-key map (kbd "M-C-a") 'ruby-beginning-of-defun)
144 (define-key map (kbd "M-C-e") 'ruby-end-of-defun)
145 (define-key map (kbd "M-C-b") 'ruby-backward-sexp) 145 (define-key map (kbd "M-C-b") 'ruby-backward-sexp)
146 (define-key map (kbd "M-C-f") 'ruby-forward-sexp) 146 (define-key map (kbd "M-C-f") 'ruby-forward-sexp)
147 (define-key map (kbd "M-C-p") 'ruby-beginning-of-block) 147 (define-key map (kbd "M-C-p") 'ruby-beginning-of-block)
148 (define-key map (kbd "M-C-n") 'ruby-end-of-block) 148 (define-key map (kbd "M-C-n") 'ruby-end-of-block)
149 (define-key map (kbd "M-C-h") 'ruby-mark-defun)
150 (define-key map (kbd "M-C-q") 'ruby-indent-exp) 149 (define-key map (kbd "M-C-q") 'ruby-indent-exp)
151 (define-key map (kbd "C-M-h") 'backward-kill-word)
152 (define-key map (kbd "C-j") 'reindent-then-newline-and-indent)
153 (define-key map (kbd "C-c {") 'ruby-toggle-block) 150 (define-key map (kbd "C-c {") 'ruby-toggle-block)
154 map) 151 map)
155 "Keymap used in Ruby mode.") 152 "Keymap used in Ruby mode.")
@@ -840,20 +837,13 @@ and `\\' when preceded by `?'."
840 (+ indent ruby-indent-level) 837 (+ indent ruby-indent-level)
841 indent)))) 838 indent))))
842 839
843(defun ruby-electric-brace (arg)
844 "Insert a brace and re-indent the current line."
845 (interactive "P")
846 (self-insert-command (prefix-numeric-value arg))
847 (ruby-indent-line t))
848
849;; TODO: Why isn't one ruby-*-of-defun written in terms of the other?
850(defun ruby-beginning-of-defun (&optional arg) 840(defun ruby-beginning-of-defun (&optional arg)
851 "Move backward to the beginning of the current top-level defun. 841 "Move backward to the beginning of the current top-level defun.
852With ARG, move backward multiple defuns. Negative ARG means 842With ARG, move backward multiple defuns. Negative ARG means
853move forward." 843move forward."
854 (interactive "p") 844 (interactive "p")
855 (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\b") 845 (and (re-search-backward (concat "^\\s *" ruby-defun-beg-re "\\_>")
856 nil 'move (or arg 1)) 846 nil t (or arg 1))
857 (beginning-of-line))) 847 (beginning-of-line)))
858 848
859(defun ruby-end-of-defun (&optional arg) 849(defun ruby-end-of-defun (&optional arg)
@@ -861,19 +851,18 @@ move forward."
861With ARG, move forward multiple defuns. Negative ARG means 851With ARG, move forward multiple defuns. Negative ARG means
862move backward." 852move backward."
863 (interactive "p") 853 (interactive "p")
864 (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)") 854 (ruby-forward-sexp)
865 nil 'move (or arg 1)) 855 (when (looking-back (concat "^\\s *" ruby-block-end-re))
866 (beginning-of-line)) 856 (forward-line 1)))
867 (forward-line 1))
868 857
869(defun ruby-beginning-of-indent () 858(defun ruby-beginning-of-indent ()
870 "TODO: document" 859 "Backtrack to a line which can be used as a reference for
871 ;; I don't understand this function. 860calculating indentation on the lines after it."
872 ;; It seems like it should move to the line where indentation should deepen, 861 (while (and (re-search-backward ruby-indent-beg-re nil 'move)
873 ;; but ruby-indent-beg-re only accounts for whitespace before class, module and def, 862 (if (ruby-in-ppss-context-p 'anything)
874 ;; so this will only match other block beginners at the beginning of the line. 863 t
875 (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\_>") nil 'move) 864 ;; We can stop, then.
876 (beginning-of-line))) 865 (beginning-of-line)))))
877 866
878(defun ruby-move-to-block (n) 867(defun ruby-move-to-block (n)
879 "Move to the beginning (N < 0) or the end (N > 0) of the current block 868 "Move to the beginning (N < 0) or the end (N > 0) of the current block
@@ -1024,15 +1013,6 @@ With ARG, do it many times. Negative ARG means move forward."
1024 ((error))) 1013 ((error)))
1025 i))) 1014 i)))
1026 1015
1027(defun ruby-mark-defun ()
1028 "Put mark at end of this Ruby function, point at beginning."
1029 (interactive)
1030 (push-mark (point))
1031 (ruby-end-of-defun)
1032 (push-mark (point) nil t)
1033 (ruby-beginning-of-defun)
1034 (re-search-backward "^\n" (- (point) 1) t))
1035
1036(defun ruby-indent-exp (&optional ignored) 1016(defun ruby-indent-exp (&optional ignored)
1037 "Indent each line in the balanced expression following the point." 1017 "Indent each line in the balanced expression following the point."
1038 (interactive "*P") 1018 (interactive "*P")
@@ -1073,7 +1053,7 @@ See `add-log-current-defun-function'."
1073 (let (mname mlist (indent 0)) 1053 (let (mname mlist (indent 0))
1074 ;; get current method (or class/module) 1054 ;; get current method (or class/module)
1075 (if (re-search-backward 1055 (if (re-search-backward
1076 (concat "^[ \t]*\\(def\\|class\\|module\\)[ \t]+" 1056 (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+"
1077 "\\(" 1057 "\\("
1078 ;; \\. and :: for class method 1058 ;; \\. and :: for class method
1079 "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" 1059 "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)"
@@ -1127,46 +1107,65 @@ See `add-log-current-defun-function'."
1127 (if mlist (concat mlist mname) mname) 1107 (if mlist (concat mlist mname) mname)
1128 mlist))))) 1108 mlist)))))
1129 1109
1130(defun ruby-brace-to-do-end () 1110(defun ruby-brace-to-do-end (orig end)
1131 (when (looking-at "{") 1111 (let (beg-marker end-marker)
1132 (let ((orig (point)) (end (progn (ruby-forward-sexp) (point)))) 1112 (goto-char end)
1133 (when (eq (char-before) ?\}) 1113 (when (eq (char-before) ?\})
1134 (delete-char -1) 1114 (delete-char -1)
1135 (if (eq (char-syntax (char-before)) ?w) 1115 (skip-chars-backward " \t")
1136 (insert " ")) 1116 (when (not (bolp))
1137 (insert "end") 1117 (insert "\n"))
1138 (if (eq (char-syntax (char-after)) ?w) 1118 (insert "end")
1139 (insert " ")) 1119 (setq end-marker (point-marker))
1140 (goto-char orig) 1120 (when (and (not (eobp)) (eq (char-syntax (char-after)) ?w))
1141 (delete-char 1) 1121 (insert " "))
1142 (if (eq (char-syntax (char-before)) ?w) 1122 (goto-char orig)
1143 (insert " ")) 1123 (delete-char 1)
1144 (insert "do") 1124 (when (eq (char-syntax (char-before)) ?w)
1145 (when (looking-at "\\sw\\||") 1125 (insert " "))
1146 (insert " ") 1126 (insert "do")
1147 (backward-char)) 1127 (setq beg-marker (point-marker))
1148 t)))) 1128 (when (looking-at "\\(\\s \\)*|")
1149 1129 (unless (match-beginning 1)
1150(defun ruby-do-end-to-brace () 1130 (insert " "))
1151 (when (and (or (bolp) 1131 (goto-char (1+ (match-end 0)))
1152 (not (memq (char-syntax (char-before)) '(?w ?_)))) 1132 (search-forward "|"))
1153 (looking-at "\\<do\\(\\s \\|$\\)")) 1133 (unless (looking-at "\\s *$")
1154 (let ((orig (point)) (end (progn (ruby-forward-sexp) (point)))) 1134 (insert "\n"))
1155 (backward-char 3) 1135 (indent-region beg-marker end-marker)
1156 (when (looking-at ruby-block-end-re) 1136 (goto-char beg-marker)
1157 (delete-char 3) 1137 t)))
1158 (insert "}") 1138
1159 (goto-char orig) 1139(defun ruby-do-end-to-brace (orig end)
1160 (delete-char 2) 1140 (goto-char (- end 3))
1161 (insert "{") 1141 (when (looking-at ruby-block-end-re)
1162 (if (looking-at "\\s +|") 1142 (delete-char 3)
1163 (delete-char (- (match-end 0) (match-beginning 0) 1))) 1143 (insert "}")
1164 t)))) 1144 (goto-char orig)
1145 (delete-char 2)
1146 (insert "{")
1147 (if (looking-at "\\s +|")
1148 (delete-char (- (match-end 0) (match-beginning 0) 1)))
1149 t))
1165 1150
1166(defun ruby-toggle-block () 1151(defun ruby-toggle-block ()
1152 "Toggle block type from do-end to braces or back.
1153The block must begin on the current line or above it and end after the point.
1154If the result is do-end block, it will always be multiline."
1167 (interactive) 1155 (interactive)
1168 (or (ruby-brace-to-do-end) 1156 (let ((start (point)) beg end)
1169 (ruby-do-end-to-brace))) 1157 (end-of-line)
1158 (unless
1159 (if (and (re-search-backward "\\({\\)\\|\\_<do\\(\\s \\|$\\||\\)")
1160 (progn
1161 (setq beg (point))
1162 (save-match-data (ruby-forward-sexp))
1163 (setq end (point))
1164 (> end start)))
1165 (if (match-beginning 1)
1166 (ruby-brace-to-do-end beg end)
1167 (ruby-do-end-to-brace beg end)))
1168 (goto-char start))))
1170 1169
1171(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit)) 1170(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit))
1172(declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit)) 1171(declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit))
@@ -1193,8 +1192,6 @@ It will be properly highlighted even when the call omits parens."))
1193 (ruby-syntax-enclosing-percent-literal end) 1192 (ruby-syntax-enclosing-percent-literal end)
1194 (funcall 1193 (funcall
1195 (syntax-propertize-rules 1194 (syntax-propertize-rules
1196 ;; #{ }, #$hoge, #@foo are not comments.
1197 ("\\(#\\)[{$@]" (1 "."))
1198 ;; $' $" $` .... are variables. 1195 ;; $' $" $` .... are variables.
1199 ;; ?' ?" ?` are ascii codes. 1196 ;; ?' ?" ?` are ascii codes.
1200 ("\\([?$]\\)[#\"'`]" 1197 ("\\([?$]\\)[#\"'`]"
@@ -1326,8 +1323,7 @@ This should only be called after matching against `ruby-here-doc-end-re'."
1326 (concat "-?\\([\"']\\|\\)" contents "\\1")))))) 1323 (concat "-?\\([\"']\\|\\)" contents "\\1"))))))
1327 1324
1328 (defconst ruby-font-lock-syntactic-keywords 1325 (defconst ruby-font-lock-syntactic-keywords
1329 `( ;; #{ }, #$hoge, #@foo are not comments 1326 `(
1330 ("\\(#\\)[{$@]" 1 (1 . nil))
1331 ;; the last $', $", $` in the respective string is not variable 1327 ;; the last $', $", $` in the respective string is not variable
1332 ;; the last ?', ?", ?` in the respective string is not ascii code 1328 ;; the last ?', ?", ?` in the respective string is not ascii code
1333 ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" 1329 ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
@@ -1549,6 +1545,9 @@ See `font-lock-syntax-table'.")
1549 ;; variables 1545 ;; variables
1550 '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>" 1546 '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>"
1551 2 font-lock-variable-name-face) 1547 2 font-lock-variable-name-face)
1548 ;; symbols
1549 '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|@?\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
1550 2 font-lock-reference-face)
1552 ;; variables 1551 ;; variables
1553 '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W" 1552 '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W"
1554 1 font-lock-variable-name-face) 1553 1 font-lock-variable-name-face)
@@ -1557,12 +1556,9 @@ See `font-lock-syntax-table'.")
1557 ;; constants 1556 ;; constants
1558 '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" 1557 '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
1559 2 font-lock-type-face) 1558 2 font-lock-type-face)
1560 ;; symbols
1561 '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
1562 2 font-lock-reference-face)
1563 '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face) 1559 '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face)
1564 ;; expression expansion 1560 ;; expression expansion
1565 '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)" 1561 '(ruby-match-expression-expansion
1566 0 font-lock-variable-name-face t) 1562 0 font-lock-variable-name-face t)
1567 ;; warn lower camel case 1563 ;; warn lower camel case
1568 ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" 1564 ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)"
@@ -1570,6 +1566,11 @@ See `font-lock-syntax-table'.")
1570 ) 1566 )
1571 "Additional expressions to highlight in Ruby mode.") 1567 "Additional expressions to highlight in Ruby mode.")
1572 1568
1569(defun ruby-match-expression-expansion (limit)
1570 (when (re-search-forward "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)" limit 'move)
1571 (or (ruby-in-ppss-context-p 'string)
1572 (ruby-match-expression-expansion limit))))
1573
1573;;;###autoload 1574;;;###autoload
1574(define-derived-mode ruby-mode prog-mode "Ruby" 1575(define-derived-mode ruby-mode prog-mode "Ruby"
1575 "Major mode for editing Ruby scripts. 1576 "Major mode for editing Ruby scripts.
@@ -1586,6 +1587,10 @@ The variable `ruby-indent-level' controls the amount of indentation.
1586 'ruby-imenu-create-index) 1587 'ruby-imenu-create-index)
1587 (set (make-local-variable 'add-log-current-defun-function) 1588 (set (make-local-variable 'add-log-current-defun-function)
1588 'ruby-add-log-current-method) 1589 'ruby-add-log-current-method)
1590 (set (make-local-variable 'beginning-of-defun-function)
1591 'ruby-beginning-of-defun)
1592 (set (make-local-variable 'end-of-defun-function)
1593 'ruby-end-of-defun)
1589 1594
1590 (add-hook 1595 (add-hook
1591 (cond ((boundp 'before-save-hook) 'before-save-hook) 1596 (cond ((boundp 'before-save-hook) 'before-save-hook)