diff options
| author | Kenichi Handa | 2010-09-16 11:11:13 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2010-09-16 11:11:13 +0900 |
| commit | 38d50547c2a8195bed0aaeafbbc4c0f277d4e416 (patch) | |
| tree | 388416c9f2cc4746d0d2d9e525a50a6c2f00f3d4 /lisp/progmodes/ruby-mode.el | |
| parent | fa3f60399014127e711f3f438004950cba0bddb9 (diff) | |
| parent | 6139f995addcb8fce63deb30c7ed0e6f2b618b02 (diff) | |
| download | emacs-38d50547c2a8195bed0aaeafbbc4c0f277d4e416.tar.gz emacs-38d50547c2a8195bed0aaeafbbc4c0f277d4e416.zip | |
merge trunk
Diffstat (limited to 'lisp/progmodes/ruby-mode.el')
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 390 |
1 files changed, 220 insertions, 170 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 0b92234bf1c..4d015de5198 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el | |||
| @@ -100,17 +100,10 @@ | |||
| 100 | 100 | ||
| 101 | (defconst ruby-block-end-re "\\<end\\>") | 101 | (defconst ruby-block-end-re "\\<end\\>") |
| 102 | 102 | ||
| 103 | (defconst ruby-here-doc-beg-re | 103 | (eval-and-compile |
| 104 | (defconst ruby-here-doc-beg-re | ||
| 104 | "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" | 105 | "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" |
| 105 | "Regexp to match the beginning of a heredoc.") | 106 | "Regexp to match the beginning of a heredoc.")) |
| 106 | |||
| 107 | (defconst ruby-here-doc-end-re | ||
| 108 | "^\\([ \t]+\\)?\\(.*\\)\\(.\\)$" | ||
| 109 | "Regexp to match the end of heredocs. | ||
| 110 | |||
| 111 | This will actually match any line with one or more characters. | ||
| 112 | It's useful in that it divides up the match string so that | ||
| 113 | `ruby-here-doc-beg-match' can search for the beginning of the heredoc.") | ||
| 114 | 107 | ||
| 115 | (defun ruby-here-doc-end-match () | 108 | (defun ruby-here-doc-end-match () |
| 116 | "Return a regexp to find the end of a heredoc. | 109 | "Return a regexp to find the end of a heredoc. |
| @@ -123,18 +116,6 @@ This should only be called after matching against `ruby-here-doc-beg-re'." | |||
| 123 | (match-string 5) | 116 | (match-string 5) |
| 124 | (match-string 6))))) | 117 | (match-string 6))))) |
| 125 | 118 | ||
| 126 | (defun ruby-here-doc-beg-match () | ||
| 127 | "Return a regexp to find the beginning of a heredoc. | ||
| 128 | |||
| 129 | This should only be called after matching against `ruby-here-doc-end-re'." | ||
| 130 | (let ((contents (regexp-quote (concat (match-string 2) (match-string 3))))) | ||
| 131 | (concat "<<" | ||
| 132 | (let ((match (match-string 1))) | ||
| 133 | (if (and match (> (length match) 0)) | ||
| 134 | (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)" (match-string 1) "\\)" | ||
| 135 | contents "\\b\\(\\1\\|\\2\\)") | ||
| 136 | (concat "-?\\([\"']\\|\\)" contents "\\b\\1")))))) | ||
| 137 | |||
| 138 | (defconst ruby-delimiter | 119 | (defconst ruby-delimiter |
| 139 | (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\(" | 120 | (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\(" |
| 140 | ruby-block-beg-re | 121 | ruby-block-beg-re |
| @@ -362,7 +343,7 @@ Also ignores spaces after parenthesis when 'space." | |||
| 362 | (back-to-indentation) | 343 | (back-to-indentation) |
| 363 | (current-column))) | 344 | (current-column))) |
| 364 | 345 | ||
| 365 | (defun ruby-indent-line (&optional flag) | 346 | (defun ruby-indent-line (&optional ignored) |
| 366 | "Correct the indentation of the current Ruby line." | 347 | "Correct the indentation of the current Ruby line." |
| 367 | (interactive) | 348 | (interactive) |
| 368 | (ruby-indent-to (ruby-calculate-indent))) | 349 | (ruby-indent-to (ruby-calculate-indent))) |
| @@ -405,8 +386,7 @@ and `\\' when preceded by `?'." | |||
| 405 | "TODO: document." | 386 | "TODO: document." |
| 406 | (save-excursion | 387 | (save-excursion |
| 407 | (store-match-data nil) | 388 | (store-match-data nil) |
| 408 | (let ((space (skip-chars-backward " \t")) | 389 | (let ((space (skip-chars-backward " \t"))) |
| 409 | (start (point))) | ||
| 410 | (cond | 390 | (cond |
| 411 | ((bolp) t) | 391 | ((bolp) t) |
| 412 | ((progn | 392 | ((progn |
| @@ -700,7 +680,7 @@ and `\\' when preceded by `?'." | |||
| 700 | (beginning-of-line) | 680 | (beginning-of-line) |
| 701 | (let ((ruby-indent-point (point)) | 681 | (let ((ruby-indent-point (point)) |
| 702 | (case-fold-search nil) | 682 | (case-fold-search nil) |
| 703 | state bol eol begin op-end | 683 | state eol begin op-end |
| 704 | (paren (progn (skip-syntax-forward " ") | 684 | (paren (progn (skip-syntax-forward " ") |
| 705 | (and (char-after) (matching-paren (char-after))))) | 685 | (and (char-after) (matching-paren (char-after))))) |
| 706 | (indent 0)) | 686 | (indent 0)) |
| @@ -780,7 +760,6 @@ and `\\' when preceded by `?'." | |||
| 780 | (if (re-search-forward "^\\s *#" end t) | 760 | (if (re-search-forward "^\\s *#" end t) |
| 781 | (beginning-of-line) | 761 | (beginning-of-line) |
| 782 | (setq done t)))) | 762 | (setq done t)))) |
| 783 | (setq bol (point)) | ||
| 784 | (end-of-line) | 763 | (end-of-line) |
| 785 | ;; skip the comment at the end | 764 | ;; skip the comment at the end |
| 786 | (skip-chars-backward " \t") | 765 | (skip-chars-backward " \t") |
| @@ -1037,10 +1016,8 @@ With ARG, do it many times. Negative ARG means move forward." | |||
| 1037 | (ruby-beginning-of-defun) | 1016 | (ruby-beginning-of-defun) |
| 1038 | (re-search-backward "^\n" (- (point) 1) t)) | 1017 | (re-search-backward "^\n" (- (point) 1) t)) |
| 1039 | 1018 | ||
| 1040 | (defun ruby-indent-exp (&optional shutup-p) | 1019 | (defun ruby-indent-exp (&optional ignored) |
| 1041 | "Indent each line in the balanced expression following the point. | 1020 | "Indent each line in the balanced expression following the point." |
| 1042 | If a prefix arg is given or SHUTUP-P is non-nil, no errors | ||
| 1043 | are signalled if a balanced expression isn't found." | ||
| 1044 | (interactive "*P") | 1021 | (interactive "*P") |
| 1045 | (let ((here (point-marker)) start top column (nest t)) | 1022 | (let ((here (point-marker)) start top column (nest t)) |
| 1046 | (set-marker-insertion-type here t) | 1023 | (set-marker-insertion-type here t) |
| @@ -1133,58 +1110,208 @@ See `add-log-current-defun-function'." | |||
| 1133 | (if mlist (concat mlist mname) mname) | 1110 | (if mlist (concat mlist mname) mname) |
| 1134 | mlist))))) | 1111 | mlist))))) |
| 1135 | 1112 | ||
| 1136 | (defconst ruby-font-lock-syntactic-keywords | 1113 | (if (eval-when-compile (fboundp #'syntax-propertize-rules)) |
| 1137 | `(;; #{ }, #$hoge, #@foo are not comments | 1114 | ;; New code that works independently from font-lock. |
| 1138 | ("\\(#\\)[{$@]" 1 (1 . nil)) | 1115 | (progn |
| 1139 | ;; the last $', $", $` in the respective string is not variable | 1116 | (defun ruby-syntax-propertize-function (start end) |
| 1140 | ;; the last ?', ?", ?` in the respective string is not ascii code | 1117 | "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." |
| 1141 | ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" | 1118 | (goto-char start) |
| 1142 | (2 (7 . nil)) | 1119 | (ruby-syntax-propertize-heredoc end) |
| 1143 | (4 (7 . nil))) | 1120 | (funcall |
| 1144 | ;; $' $" $` .... are variables | 1121 | (syntax-propertize-rules |
| 1145 | ;; ?' ?" ?` are ascii codes | 1122 | ;; #{ }, #$hoge, #@foo are not comments |
| 1146 | ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil)) | 1123 | ("\\(#\\)[{$@]" (1 ".")) |
| 1147 | ;; regexps | 1124 | ;; the last $', $", $` in the respective string is not variable |
| 1148 | ("\\(^\\|[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" | 1125 | ;; the last ?', ?", ?` in the respective string is not ascii code |
| 1149 | (4 (7 . ?/)) | 1126 | ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" |
| 1150 | (6 (7 . ?/))) | 1127 | (2 "\"") |
| 1151 | ("^=en\\(d\\)\\_>" 1 "!") | 1128 | (4 "\"")) |
| 1152 | ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax)) | 1129 | ;; $' $" $` .... are variables |
| 1153 | ;; Currently, the following case is highlighted incorrectly: | 1130 | ;; ?' ?" ?` are ascii codes |
| 1154 | ;; | 1131 | ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" (3 ".")) |
| 1155 | ;; <<FOO | 1132 | ;; regexps |
| 1156 | ;; FOO | 1133 | ("\\(^\\|[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" |
| 1157 | ;; <<BAR | 1134 | (4 "\"/") |
| 1158 | ;; <<BAZ | 1135 | (6 "\"/")) |
| 1159 | ;; BAZ | 1136 | ("^=en\\(d\\)\\_>" (1 "!")) |
| 1160 | ;; BAR | 1137 | ("^\\(=\\)begin\\_>" (1 "!")) |
| 1161 | ;; | 1138 | ;; Handle here documents. |
| 1162 | ;; This is because all here-doc beginnings are highlighted before any endings, | 1139 | ((concat ruby-here-doc-beg-re ".*\\(\n\\)") |
| 1163 | ;; so although <<BAR is properly marked as a beginning, when we get to <<BAZ | 1140 | (7 (prog1 "\"" (ruby-syntax-propertize-heredoc end))))) |
| 1164 | ;; it thinks <<BAR is part of a string so it's marked as well. | 1141 | (point) end)) |
| 1165 | ;; | 1142 | |
| 1166 | ;; This may be fixable by modifying ruby-in-here-doc-p to use | 1143 | (defun ruby-syntax-propertize-heredoc (limit) |
| 1167 | ;; ruby-in-non-here-doc-string-p rather than syntax-ppss-context, | 1144 | (let ((ppss (syntax-ppss)) |
| 1168 | ;; but I don't want to try that until we've got unit tests set up | 1145 | (res '())) |
| 1169 | ;; to make sure I don't break anything else. | 1146 | (when (eq ?\n (nth 3 ppss)) |
| 1170 | (,(concat ruby-here-doc-beg-re ".*\\(\n\\)") | 1147 | (save-excursion |
| 1171 | ,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re)) | 1148 | (goto-char (nth 8 ppss)) |
| 1172 | (ruby-here-doc-beg-syntax)) | 1149 | (beginning-of-line) |
| 1173 | (,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax))) | 1150 | (while (re-search-forward ruby-here-doc-beg-re |
| 1174 | "Syntactic keywords for Ruby mode. See `font-lock-syntactic-keywords'.") | 1151 | (line-end-position) t) |
| 1175 | 1152 | (push (concat (ruby-here-doc-end-match) "\n") res))) | |
| 1176 | (defun ruby-comment-beg-syntax () | 1153 | (let ((start (point))) |
| 1177 | "Return the syntax cell for a the first character of a =begin. | 1154 | ;; With multiple openers on the same line, we don't know in which |
| 1155 | ;; part `start' is, so we have to go back to the beginning. | ||
| 1156 | (when (cdr res) | ||
| 1157 | (goto-char (nth 8 ppss)) | ||
| 1158 | (setq res (nreverse res))) | ||
| 1159 | (while (and res (re-search-forward (pop res) limit 'move)) | ||
| 1160 | (if (null res) | ||
| 1161 | (put-text-property (1- (point)) (point) | ||
| 1162 | 'syntax-table (string-to-syntax "\"")))) | ||
| 1163 | ;; Make extra sure we don't move back, lest we could fall into an | ||
| 1164 | ;; inf-loop. | ||
| 1165 | (if (< (point) start) (goto-char start)))))) | ||
| 1166 | ) | ||
| 1167 | |||
| 1168 | ;; For Emacsen where syntax-propertize-rules is not (yet) available, | ||
| 1169 | ;; fallback on the old font-lock-syntactic-keywords stuff. | ||
| 1170 | |||
| 1171 | (defconst ruby-here-doc-end-re | ||
| 1172 | "^\\([ \t]+\\)?\\(.*\\)\\(\n\\)" | ||
| 1173 | "Regexp to match the end of heredocs. | ||
| 1174 | |||
| 1175 | This will actually match any line with one or more characters. | ||
| 1176 | It's useful in that it divides up the match string so that | ||
| 1177 | `ruby-here-doc-beg-match' can search for the beginning of the heredoc.") | ||
| 1178 | |||
| 1179 | (defun ruby-here-doc-beg-match () | ||
| 1180 | "Return a regexp to find the beginning of a heredoc. | ||
| 1181 | |||
| 1182 | This should only be called after matching against `ruby-here-doc-end-re'." | ||
| 1183 | (let ((contents (regexp-quote (match-string 2)))) | ||
| 1184 | (concat "<<" | ||
| 1185 | (let ((match (match-string 1))) | ||
| 1186 | (if (and match (> (length match) 0)) | ||
| 1187 | (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)" match "\\)" | ||
| 1188 | contents "\\b\\(\\1\\|\\2\\)") | ||
| 1189 | (concat "-?\\([\"']\\|\\)" contents "\\b\\1")))))) | ||
| 1190 | |||
| 1191 | (defconst ruby-font-lock-syntactic-keywords | ||
| 1192 | `( ;; #{ }, #$hoge, #@foo are not comments | ||
| 1193 | ("\\(#\\)[{$@]" 1 (1 . nil)) | ||
| 1194 | ;; the last $', $", $` in the respective string is not variable | ||
| 1195 | ;; the last ?', ?", ?` in the respective string is not ascii code | ||
| 1196 | ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" | ||
| 1197 | (2 (7 . nil)) | ||
| 1198 | (4 (7 . nil))) | ||
| 1199 | ;; $' $" $` .... are variables | ||
| 1200 | ;; ?' ?" ?` are ascii codes | ||
| 1201 | ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil)) | ||
| 1202 | ;; regexps | ||
| 1203 | ("\\(^\\|[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" | ||
| 1204 | (4 (7 . ?/)) | ||
| 1205 | (6 (7 . ?/))) | ||
| 1206 | ("^=en\\(d\\)\\_>" 1 "!") | ||
| 1207 | ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax)) | ||
| 1208 | ;; Currently, the following case is highlighted incorrectly: | ||
| 1209 | ;; | ||
| 1210 | ;; <<FOO | ||
| 1211 | ;; FOO | ||
| 1212 | ;; <<BAR | ||
| 1213 | ;; <<BAZ | ||
| 1214 | ;; BAZ | ||
| 1215 | ;; BAR | ||
| 1216 | ;; | ||
| 1217 | ;; This is because all here-doc beginnings are highlighted before any endings, | ||
| 1218 | ;; so although <<BAR is properly marked as a beginning, when we get to <<BAZ | ||
| 1219 | ;; it thinks <<BAR is part of a string so it's marked as well. | ||
| 1220 | ;; | ||
| 1221 | ;; This may be fixable by modifying ruby-in-here-doc-p to use | ||
| 1222 | ;; ruby-in-non-here-doc-string-p rather than syntax-ppss-context, | ||
| 1223 | ;; but I don't want to try that until we've got unit tests set up | ||
| 1224 | ;; to make sure I don't break anything else. | ||
| 1225 | (,(concat ruby-here-doc-beg-re ".*\\(\n\\)") | ||
| 1226 | ,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re)) | ||
| 1227 | (ruby-here-doc-beg-syntax)) | ||
| 1228 | (,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax))) | ||
| 1229 | "Syntactic keywords for Ruby mode. See `font-lock-syntactic-keywords'.") | ||
| 1230 | |||
| 1231 | (defun ruby-comment-beg-syntax () | ||
| 1232 | "Return the syntax cell for a the first character of a =begin. | ||
| 1178 | See the definition of `ruby-font-lock-syntactic-keywords'. | 1233 | See the definition of `ruby-font-lock-syntactic-keywords'. |
| 1179 | 1234 | ||
| 1180 | This returns a comment-delimiter cell as long as the =begin | 1235 | This returns a comment-delimiter cell as long as the =begin |
| 1181 | isn't in a string or another comment." | 1236 | isn't in a string or another comment." |
| 1182 | (when (not (nth 3 (syntax-ppss))) | 1237 | (when (not (nth 3 (syntax-ppss))) |
| 1183 | (string-to-syntax "!"))) | 1238 | (string-to-syntax "!"))) |
| 1239 | |||
| 1240 | (defun ruby-in-here-doc-p () | ||
| 1241 | "Return whether or not the point is in a heredoc." | ||
| 1242 | (save-excursion | ||
| 1243 | (let ((old-point (point)) (case-fold-search nil)) | ||
| 1244 | (beginning-of-line) | ||
| 1245 | (catch 'found-beg | ||
| 1246 | (while (re-search-backward ruby-here-doc-beg-re nil t) | ||
| 1247 | (if (not (or (ruby-in-ppss-context-p 'anything) | ||
| 1248 | (ruby-here-doc-find-end old-point))) | ||
| 1249 | (throw 'found-beg t))))))) | ||
| 1250 | |||
| 1251 | (defun ruby-here-doc-find-end (&optional limit) | ||
| 1252 | "Expects the point to be on a line with one or more heredoc openers. | ||
| 1253 | Returns the buffer position at which all heredocs on the line | ||
| 1254 | are terminated, or nil if they aren't terminated before the | ||
| 1255 | buffer position `limit' or the end of the buffer." | ||
| 1256 | (save-excursion | ||
| 1257 | (beginning-of-line) | ||
| 1258 | (catch 'done | ||
| 1259 | (let ((eol (save-excursion (end-of-line) (point))) | ||
| 1260 | (case-fold-search nil) | ||
| 1261 | ;; Fake match data such that (match-end 0) is at eol | ||
| 1262 | (end-match-data (progn (looking-at ".*$") (match-data))) | ||
| 1263 | beg-match-data end-re) | ||
| 1264 | (while (re-search-forward ruby-here-doc-beg-re eol t) | ||
| 1265 | (setq beg-match-data (match-data)) | ||
| 1266 | (setq end-re (ruby-here-doc-end-match)) | ||
| 1267 | |||
| 1268 | (set-match-data end-match-data) | ||
| 1269 | (goto-char (match-end 0)) | ||
| 1270 | (unless (re-search-forward end-re limit t) (throw 'done nil)) | ||
| 1271 | (setq end-match-data (match-data)) | ||
| 1272 | |||
| 1273 | (set-match-data beg-match-data) | ||
| 1274 | (goto-char (match-end 0))) | ||
| 1275 | (set-match-data end-match-data) | ||
| 1276 | (goto-char (match-end 0)) | ||
| 1277 | (point))))) | ||
| 1278 | |||
| 1279 | (defun ruby-here-doc-beg-syntax () | ||
| 1280 | "Return the syntax cell for a line that may begin a heredoc. | ||
| 1281 | See the definition of `ruby-font-lock-syntactic-keywords'. | ||
| 1282 | |||
| 1283 | This sets the syntax cell for the newline ending the line | ||
| 1284 | containing the heredoc beginning so that cases where multiple | ||
| 1285 | heredocs are started on one line are handled correctly." | ||
| 1286 | (save-excursion | ||
| 1287 | (goto-char (match-beginning 0)) | ||
| 1288 | (unless (or (ruby-in-ppss-context-p 'non-heredoc) | ||
| 1289 | (ruby-in-here-doc-p)) | ||
| 1290 | (string-to-syntax "\"")))) | ||
| 1291 | |||
| 1292 | (defun ruby-here-doc-end-syntax () | ||
| 1293 | "Return the syntax cell for a line that may end a heredoc. | ||
| 1294 | See the definition of `ruby-font-lock-syntactic-keywords'." | ||
| 1295 | (let ((pss (syntax-ppss)) (case-fold-search nil)) | ||
| 1296 | ;; If we aren't in a string, we definitely aren't ending a heredoc, | ||
| 1297 | ;; so we can just give up. | ||
| 1298 | ;; This means we aren't doing a full-document search | ||
| 1299 | ;; every time we enter a character. | ||
| 1300 | (when (ruby-in-ppss-context-p 'heredoc pss) | ||
| 1301 | (save-excursion | ||
| 1302 | (goto-char (nth 8 pss)) ; Go to the beginning of heredoc. | ||
| 1303 | (let ((eol (point))) | ||
| 1304 | (beginning-of-line) | ||
| 1305 | (if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line... | ||
| 1306 | (not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment... | ||
| 1307 | (progn (goto-char (match-end 0)) ; And it's the last heredoc on its line... | ||
| 1308 | (not (re-search-forward ruby-here-doc-beg-re eol t)))) | ||
| 1309 | (string-to-syntax "\""))))))) | ||
| 1184 | 1310 | ||
| 1185 | (unless (functionp 'syntax-ppss) | 1311 | (unless (functionp 'syntax-ppss) |
| 1186 | (defun syntax-ppss (&optional pos) | 1312 | (defun syntax-ppss (&optional pos) |
| 1187 | (parse-partial-sexp (point-min) (or pos (point))))) | 1313 | (parse-partial-sexp (point-min) (or pos (point))))) |
| 1314 | ) | ||
| 1188 | 1315 | ||
| 1189 | (defun ruby-in-ppss-context-p (context &optional ppss) | 1316 | (defun ruby-in-ppss-context-p (context &optional ppss) |
| 1190 | (let ((ppss (or ppss (syntax-ppss (point))))) | 1317 | (let ((ppss (or ppss (syntax-ppss (point))))) |
| @@ -1195,10 +1322,7 @@ isn't in a string or another comment." | |||
| 1195 | ((eq context 'string) | 1322 | ((eq context 'string) |
| 1196 | (nth 3 ppss)) | 1323 | (nth 3 ppss)) |
| 1197 | ((eq context 'heredoc) | 1324 | ((eq context 'heredoc) |
| 1198 | (and (nth 3 ppss) | 1325 | (eq ?\n (nth 3 ppss))) |
| 1199 | ;; If it's generic string, it's a heredoc and we don't care | ||
| 1200 | ;; See `parse-partial-sexp' | ||
| 1201 | (not (numberp (nth 3 ppss))))) | ||
| 1202 | ((eq context 'non-heredoc) | 1326 | ((eq context 'non-heredoc) |
| 1203 | (and (ruby-in-ppss-context-p 'anything) | 1327 | (and (ruby-in-ppss-context-p 'anything) |
| 1204 | (not (ruby-in-ppss-context-p 'heredoc)))) | 1328 | (not (ruby-in-ppss-context-p 'heredoc)))) |
| @@ -1210,77 +1334,6 @@ isn't in a string or another comment." | |||
| 1210 | "context name `" (symbol-name context) "' is unknown")))) | 1334 | "context name `" (symbol-name context) "' is unknown")))) |
| 1211 | t))) | 1335 | t))) |
| 1212 | 1336 | ||
| 1213 | (defun ruby-in-here-doc-p () | ||
| 1214 | "Return whether or not the point is in a heredoc." | ||
| 1215 | (save-excursion | ||
| 1216 | (let ((old-point (point)) (case-fold-search nil)) | ||
| 1217 | (beginning-of-line) | ||
| 1218 | (catch 'found-beg | ||
| 1219 | (while (re-search-backward ruby-here-doc-beg-re nil t) | ||
| 1220 | (if (not (or (ruby-in-ppss-context-p 'anything) | ||
| 1221 | (ruby-here-doc-find-end old-point))) | ||
| 1222 | (throw 'found-beg t))))))) | ||
| 1223 | |||
| 1224 | (defun ruby-here-doc-find-end (&optional limit) | ||
| 1225 | "Expects the point to be on a line with one or more heredoc openers. | ||
| 1226 | Returns the buffer position at which all heredocs on the line | ||
| 1227 | are terminated, or nil if they aren't terminated before the | ||
| 1228 | buffer position `limit' or the end of the buffer." | ||
| 1229 | (save-excursion | ||
| 1230 | (beginning-of-line) | ||
| 1231 | (catch 'done | ||
| 1232 | (let ((eol (save-excursion (end-of-line) (point))) | ||
| 1233 | (case-fold-search nil) | ||
| 1234 | ;; Fake match data such that (match-end 0) is at eol | ||
| 1235 | (end-match-data (progn (looking-at ".*$") (match-data))) | ||
| 1236 | beg-match-data end-re) | ||
| 1237 | (while (re-search-forward ruby-here-doc-beg-re eol t) | ||
| 1238 | (setq beg-match-data (match-data)) | ||
| 1239 | (setq end-re (ruby-here-doc-end-match)) | ||
| 1240 | |||
| 1241 | (set-match-data end-match-data) | ||
| 1242 | (goto-char (match-end 0)) | ||
| 1243 | (unless (re-search-forward end-re limit t) (throw 'done nil)) | ||
| 1244 | (setq end-match-data (match-data)) | ||
| 1245 | |||
| 1246 | (set-match-data beg-match-data) | ||
| 1247 | (goto-char (match-end 0))) | ||
| 1248 | (set-match-data end-match-data) | ||
| 1249 | (goto-char (match-end 0)) | ||
| 1250 | (point))))) | ||
| 1251 | |||
| 1252 | (defun ruby-here-doc-beg-syntax () | ||
| 1253 | "Return the syntax cell for a line that may begin a heredoc. | ||
| 1254 | See the definition of `ruby-font-lock-syntactic-keywords'. | ||
| 1255 | |||
| 1256 | This sets the syntax cell for the newline ending the line | ||
| 1257 | containing the heredoc beginning so that cases where multiple | ||
| 1258 | heredocs are started on one line are handled correctly." | ||
| 1259 | (save-excursion | ||
| 1260 | (goto-char (match-beginning 0)) | ||
| 1261 | (unless (or (ruby-in-ppss-context-p 'non-heredoc) | ||
| 1262 | (ruby-in-here-doc-p)) | ||
| 1263 | (string-to-syntax "|")))) | ||
| 1264 | |||
| 1265 | (defun ruby-here-doc-end-syntax () | ||
| 1266 | "Return the syntax cell for a line that may end a heredoc. | ||
| 1267 | See the definition of `ruby-font-lock-syntactic-keywords'." | ||
| 1268 | (let ((pss (syntax-ppss)) (case-fold-search nil)) | ||
| 1269 | ;; If we aren't in a string, we definitely aren't ending a heredoc, | ||
| 1270 | ;; so we can just give up. | ||
| 1271 | ;; This means we aren't doing a full-document search | ||
| 1272 | ;; every time we enter a character. | ||
| 1273 | (when (ruby-in-ppss-context-p 'heredoc pss) | ||
| 1274 | (save-excursion | ||
| 1275 | (goto-char (nth 8 pss)) ; Go to the beginning of heredoc. | ||
| 1276 | (let ((eol (point))) | ||
| 1277 | (beginning-of-line) | ||
| 1278 | (if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line... | ||
| 1279 | (not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment... | ||
| 1280 | (progn (goto-char (match-end 0)) ; And it's the last heredoc on its line... | ||
| 1281 | (not (re-search-forward ruby-here-doc-beg-re eol t)))) | ||
| 1282 | (string-to-syntax "|"))))))) | ||
| 1283 | |||
| 1284 | (if (featurep 'xemacs) | 1337 | (if (featurep 'xemacs) |
| 1285 | (put 'ruby-mode 'font-lock-defaults | 1338 | (put 'ruby-mode 'font-lock-defaults |
| 1286 | '((ruby-font-lock-keywords) | 1339 | '((ruby-font-lock-keywords) |
| @@ -1377,8 +1430,10 @@ See `font-lock-syntax-table'.") | |||
| 1377 | ) | 1430 | ) |
| 1378 | "Additional expressions to highlight in Ruby mode.") | 1431 | "Additional expressions to highlight in Ruby mode.") |
| 1379 | 1432 | ||
| 1433 | (defvar electric-indent-chars) | ||
| 1434 | |||
| 1380 | ;;;###autoload | 1435 | ;;;###autoload |
| 1381 | (defun ruby-mode () | 1436 | (define-derived-mode ruby-mode prog-mode "Ruby" |
| 1382 | "Major mode for editing Ruby scripts. | 1437 | "Major mode for editing Ruby scripts. |
| 1383 | \\[ruby-indent-line] properly indents subexpressions of multi-line | 1438 | \\[ruby-indent-line] properly indents subexpressions of multi-line |
| 1384 | class, module, def, if, while, for, do, and case statements, taking | 1439 | class, module, def, if, while, for, do, and case statements, taking |
| @@ -1387,27 +1442,22 @@ nesting into account. | |||
| 1387 | The variable `ruby-indent-level' controls the amount of indentation. | 1442 | The variable `ruby-indent-level' controls the amount of indentation. |
| 1388 | 1443 | ||
| 1389 | \\{ruby-mode-map}" | 1444 | \\{ruby-mode-map}" |
| 1390 | (interactive) | ||
| 1391 | (kill-all-local-variables) | ||
| 1392 | (use-local-map ruby-mode-map) | ||
| 1393 | (setq mode-name "Ruby") | ||
| 1394 | (setq major-mode 'ruby-mode) | ||
| 1395 | (ruby-mode-variables) | 1445 | (ruby-mode-variables) |
| 1396 | 1446 | ||
| 1397 | (set (make-local-variable 'indent-line-function) | ||
| 1398 | 'ruby-indent-line) | ||
| 1399 | (set (make-local-variable 'imenu-create-index-function) | 1447 | (set (make-local-variable 'imenu-create-index-function) |
| 1400 | 'ruby-imenu-create-index) | 1448 | 'ruby-imenu-create-index) |
| 1401 | (set (make-local-variable 'add-log-current-defun-function) | 1449 | (set (make-local-variable 'add-log-current-defun-function) |
| 1402 | 'ruby-add-log-current-method) | 1450 | 'ruby-add-log-current-method) |
| 1403 | 1451 | ||
| 1404 | (add-hook | 1452 | (add-hook |
| 1405 | (cond ((boundp 'before-save-hook) | 1453 | (cond ((boundp 'before-save-hook) 'before-save-hook) |
| 1406 | (make-local-variable 'before-save-hook) | ||
| 1407 | 'before-save-hook) | ||
| 1408 | ((boundp 'write-contents-functions) 'write-contents-functions) | 1454 | ((boundp 'write-contents-functions) 'write-contents-functions) |
| 1409 | ((boundp 'write-contents-hooks) 'write-contents-hooks)) | 1455 | ((boundp 'write-contents-hooks) 'write-contents-hooks)) |
| 1410 | 'ruby-mode-set-encoding) | 1456 | 'ruby-mode-set-encoding nil 'local) |
| 1457 | |||
| 1458 | (set (make-local-variable 'electric-indent-chars) | ||
| 1459 | (append '(?\{ ?\}) (if (boundp 'electric-indent-chars) | ||
| 1460 | (default-value 'electric-indent-chars)))) | ||
| 1411 | 1461 | ||
| 1412 | (set (make-local-variable 'font-lock-defaults) | 1462 | (set (make-local-variable 'font-lock-defaults) |
| 1413 | '((ruby-font-lock-keywords) nil nil)) | 1463 | '((ruby-font-lock-keywords) nil nil)) |
| @@ -1415,12 +1465,12 @@ The variable `ruby-indent-level' controls the amount of indentation. | |||
| 1415 | ruby-font-lock-keywords) | 1465 | ruby-font-lock-keywords) |
| 1416 | (set (make-local-variable 'font-lock-syntax-table) | 1466 | (set (make-local-variable 'font-lock-syntax-table) |
| 1417 | ruby-font-lock-syntax-table) | 1467 | ruby-font-lock-syntax-table) |
| 1418 | (set (make-local-variable 'font-lock-syntactic-keywords) | ||
| 1419 | ruby-font-lock-syntactic-keywords) | ||
| 1420 | 1468 | ||
| 1421 | (if (fboundp 'run-mode-hooks) | 1469 | (if (eval-when-compile (fboundp 'syntax-propertize-rules)) |
| 1422 | (run-mode-hooks 'ruby-mode-hook) | 1470 | (set (make-local-variable 'syntax-propertize-function) |
| 1423 | (run-hooks 'ruby-mode-hook))) | 1471 | #'ruby-syntax-propertize-function) |
| 1472 | (set (make-local-variable 'font-lock-syntactic-keywords) | ||
| 1473 | ruby-font-lock-syntactic-keywords))) | ||
| 1424 | 1474 | ||
| 1425 | ;;; Invoke ruby-mode when appropriate | 1475 | ;;; Invoke ruby-mode when appropriate |
| 1426 | 1476 | ||