diff options
| author | Tom Tromey | 2013-06-03 12:25:05 -0600 |
|---|---|---|
| committer | Tom Tromey | 2013-06-03 12:25:05 -0600 |
| commit | 68359abba96d7ec4db8aab3d3dd9cf1105c3bab5 (patch) | |
| tree | 862703e7e1a1888170136a8296a5750d6b2ae2eb /lisp/progmodes/ruby-mode.el | |
| parent | cbcba8ce7f980b01c18c0fd561ef6687b1361507 (diff) | |
| parent | e2d8a6f0a229b4ebe26484b892ec4f14888f58b6 (diff) | |
| download | emacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.tar.gz emacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.zip | |
merge from trunk; clean up some issues
Diffstat (limited to 'lisp/progmodes/ruby-mode.el')
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 351 |
1 files changed, 250 insertions, 101 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 6e471d1aa2a..fa4efe49b7b 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el | |||
| @@ -113,7 +113,7 @@ | |||
| 113 | "Regexp to match the beginning of a heredoc.") | 113 | "Regexp to match the beginning of a heredoc.") |
| 114 | 114 | ||
| 115 | (defconst ruby-expression-expansion-re | 115 | (defconst ruby-expression-expansion-re |
| 116 | "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)")) | 116 | "\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)")) |
| 117 | 117 | ||
| 118 | (defun ruby-here-doc-end-match () | 118 | (defun ruby-here-doc-end-match () |
| 119 | "Return a regexp to find the end of a heredoc. | 119 | "Return a regexp to find the end of a heredoc. |
| @@ -148,13 +148,16 @@ This should only be called after matching against `ruby-here-doc-beg-re'." | |||
| 148 | (define-abbrev-table 'ruby-mode-abbrev-table () | 148 | (define-abbrev-table 'ruby-mode-abbrev-table () |
| 149 | "Abbrev table in use in Ruby mode buffers.") | 149 | "Abbrev table in use in Ruby mode buffers.") |
| 150 | 150 | ||
| 151 | (defvar ruby-use-smie nil) | ||
| 152 | |||
| 151 | (defvar ruby-mode-map | 153 | (defvar ruby-mode-map |
| 152 | (let ((map (make-sparse-keymap))) | 154 | (let ((map (make-sparse-keymap))) |
| 153 | (define-key map (kbd "M-C-b") 'ruby-backward-sexp) | 155 | (unless ruby-use-smie |
| 154 | (define-key map (kbd "M-C-f") 'ruby-forward-sexp) | 156 | (define-key map (kbd "M-C-b") 'ruby-backward-sexp) |
| 157 | (define-key map (kbd "M-C-f") 'ruby-forward-sexp) | ||
| 158 | (define-key map (kbd "M-C-q") 'ruby-indent-exp)) | ||
| 155 | (define-key map (kbd "M-C-p") 'ruby-beginning-of-block) | 159 | (define-key map (kbd "M-C-p") 'ruby-beginning-of-block) |
| 156 | (define-key map (kbd "M-C-n") 'ruby-end-of-block) | 160 | (define-key map (kbd "M-C-n") 'ruby-end-of-block) |
| 157 | (define-key map (kbd "M-C-q") 'ruby-indent-exp) | ||
| 158 | (define-key map (kbd "C-c {") 'ruby-toggle-block) | 161 | (define-key map (kbd "C-c {") 'ruby-toggle-block) |
| 159 | map) | 162 | map) |
| 160 | "Keymap used in Ruby mode.") | 163 | "Keymap used in Ruby mode.") |
| @@ -236,6 +239,111 @@ Also ignores spaces after parenthesis when 'space." | |||
| 236 | (put 'ruby-comment-column 'safe-local-variable 'integerp) | 239 | (put 'ruby-comment-column 'safe-local-variable 'integerp) |
| 237 | (put 'ruby-deep-arglist 'safe-local-variable 'booleanp) | 240 | (put 'ruby-deep-arglist 'safe-local-variable 'booleanp) |
| 238 | 241 | ||
| 242 | ;;; SMIE support | ||
| 243 | |||
| 244 | (require 'smie) | ||
| 245 | |||
| 246 | (defconst ruby-smie-grammar | ||
| 247 | ;; FIXME: Add support for Cucumber. | ||
| 248 | (smie-prec2->grammar | ||
| 249 | (smie-bnf->prec2 | ||
| 250 | '((id) | ||
| 251 | (insts (inst) (insts ";" insts)) | ||
| 252 | (inst (exp) (inst "iuwu-mod" exp)) | ||
| 253 | (exp (exp1) (exp "," exp)) | ||
| 254 | (exp1 (exp2) (exp2 "?" exp1 ":" exp1)) | ||
| 255 | (exp2 ("def" insts "end") | ||
| 256 | ("begin" insts-rescue-insts "end") | ||
| 257 | ("do" insts "end") | ||
| 258 | ("class" insts "end") ("module" insts "end") | ||
| 259 | ("for" for-body "end") | ||
| 260 | ("[" expseq "]") | ||
| 261 | ("{" hashvals "}") | ||
| 262 | ("while" insts "end") | ||
| 263 | ("until" insts "end") | ||
| 264 | ("unless" insts "end") | ||
| 265 | ("if" if-body "end") | ||
| 266 | ("case" cases "end")) | ||
| 267 | (for-body (for-head ";" insts)) | ||
| 268 | (for-head (id "in" exp)) | ||
| 269 | (cases (exp "then" insts) ;; FIXME: Ruby also allows (exp ":" insts). | ||
| 270 | (cases "when" cases) (insts "else" insts)) | ||
| 271 | (expseq (exp) );;(expseq "," expseq) | ||
| 272 | (hashvals (id "=>" exp1) (hashvals "," hashvals)) | ||
| 273 | (insts-rescue-insts (insts) | ||
| 274 | (insts-rescue-insts "rescue" insts-rescue-insts) | ||
| 275 | (insts-rescue-insts "ensure" insts-rescue-insts)) | ||
| 276 | (itheni (insts) (exp "then" insts)) | ||
| 277 | (ielsei (itheni) (itheni "else" insts)) | ||
| 278 | (if-body (ielsei) (if-body "elsif" if-body))) | ||
| 279 | '((nonassoc "in") (assoc ";") (assoc ",")) | ||
| 280 | '((assoc "when")) | ||
| 281 | '((assoc "elsif")) | ||
| 282 | '((assoc "rescue" "ensure")) | ||
| 283 | '((assoc ","))))) | ||
| 284 | |||
| 285 | (defun ruby-smie--bosp () | ||
| 286 | (save-excursion (skip-chars-backward " \t") | ||
| 287 | (or (bolp) (eq (char-before) ?\;)))) | ||
| 288 | |||
| 289 | (defun ruby-smie--implicit-semi-p () | ||
| 290 | (save-excursion | ||
| 291 | (skip-chars-backward " \t") | ||
| 292 | (not (or (bolp) | ||
| 293 | (memq (char-before) '(?\; ?- ?+ ?* ?/ ?:)) | ||
| 294 | (and (memq (char-before) '(?\? ?=)) | ||
| 295 | (not (memq (char-syntax (char-before (1- (point)))) | ||
| 296 | '(?w ?_)))))))) | ||
| 297 | |||
| 298 | (defun ruby-smie--forward-token () | ||
| 299 | (skip-chars-forward " \t") | ||
| 300 | (if (and (looking-at "[\n#]") | ||
| 301 | ;; Only add implicit ; when needed. | ||
| 302 | (ruby-smie--implicit-semi-p)) | ||
| 303 | (progn | ||
| 304 | (if (eolp) (forward-char 1) (forward-comment 1)) | ||
| 305 | ";") | ||
| 306 | (forward-comment (point-max)) | ||
| 307 | (let ((tok (smie-default-forward-token))) | ||
| 308 | (cond | ||
| 309 | ((member tok '("unless" "if" "while" "until")) | ||
| 310 | (if (save-excursion (forward-word -1) (ruby-smie--bosp)) | ||
| 311 | tok "iuwu-mod")) | ||
| 312 | (t tok))))) | ||
| 313 | |||
| 314 | (defun ruby-smie--backward-token () | ||
| 315 | (let ((pos (point))) | ||
| 316 | (forward-comment (- (point))) | ||
| 317 | (if (and (> pos (line-end-position)) | ||
| 318 | (ruby-smie--implicit-semi-p)) | ||
| 319 | (progn (skip-chars-forward " \t") | ||
| 320 | ";") | ||
| 321 | (let ((tok (smie-default-backward-token))) | ||
| 322 | (cond | ||
| 323 | ((member tok '("unless" "if" "while" "until")) | ||
| 324 | (if (ruby-smie--bosp) | ||
| 325 | tok "iuwu-mod")) | ||
| 326 | (t tok)))))) | ||
| 327 | |||
| 328 | (defun ruby-smie-rules (kind token) | ||
| 329 | (pcase (cons kind token) | ||
| 330 | (`(:elem . basic) ruby-indent-level) | ||
| 331 | (`(:after . ";") | ||
| 332 | (if (smie-rule-parent-p "def" "begin" "do" "class" "module" "for" | ||
| 333 | "[" "{" "while" "until" "unless" | ||
| 334 | "if" "then" "elsif" "else" "when" | ||
| 335 | "rescue" "ensure") | ||
| 336 | (smie-rule-parent ruby-indent-level) | ||
| 337 | ;; For (invalid) code between switch and case. | ||
| 338 | ;; (if (smie-parent-p "switch") 4) | ||
| 339 | 0)) | ||
| 340 | (`(:before . ,(or `"else" `"then" `"elsif")) 0) | ||
| 341 | (`(:before . ,(or `"when")) | ||
| 342 | (if (not (smie-rule-sibling-p)) 0)) ;; ruby-indent-level | ||
| 343 | ;; Hack attack: Since newlines are separators, don't try to align args that | ||
| 344 | ;; appear on a separate line. | ||
| 345 | (`(:list-intro . ";") t))) | ||
| 346 | |||
| 239 | (defun ruby-imenu-create-index-in-block (prefix beg end) | 347 | (defun ruby-imenu-create-index-in-block (prefix beg end) |
| 240 | "Create an imenu index of methods inside a block." | 348 | "Create an imenu index of methods inside a block." |
| 241 | (let ((index-alist '()) (case-fold-search nil) | 349 | (let ((index-alist '()) (case-fold-search nil) |
| @@ -290,7 +398,11 @@ Also ignores spaces after parenthesis when 'space." | |||
| 290 | (set-syntax-table ruby-mode-syntax-table) | 398 | (set-syntax-table ruby-mode-syntax-table) |
| 291 | (setq local-abbrev-table ruby-mode-abbrev-table) | 399 | (setq local-abbrev-table ruby-mode-abbrev-table) |
| 292 | (setq indent-tabs-mode ruby-indent-tabs-mode) | 400 | (setq indent-tabs-mode ruby-indent-tabs-mode) |
| 293 | (set (make-local-variable 'indent-line-function) 'ruby-indent-line) | 401 | (if ruby-use-smie |
| 402 | (smie-setup ruby-smie-grammar #'ruby-smie-rules | ||
| 403 | :forward-token #'ruby-smie--forward-token | ||
| 404 | :backward-token #'ruby-smie--backward-token) | ||
| 405 | (set (make-local-variable 'indent-line-function) 'ruby-indent-line)) | ||
| 294 | (set (make-local-variable 'require-final-newline) t) | 406 | (set (make-local-variable 'require-final-newline) t) |
| 295 | (set (make-local-variable 'comment-start) "# ") | 407 | (set (make-local-variable 'comment-start) "# ") |
| 296 | (set (make-local-variable 'comment-end) "") | 408 | (set (make-local-variable 'comment-end) "") |
| @@ -847,22 +959,24 @@ Can be one of `heredoc', `modifier', `expr-qstr', `expr-re'." | |||
| 847 | indent)))) | 959 | indent)))) |
| 848 | 960 | ||
| 849 | (defun ruby-beginning-of-defun (&optional arg) | 961 | (defun ruby-beginning-of-defun (&optional arg) |
| 850 | "Move backward to the beginning of the current top-level defun. | 962 | "Move backward to the beginning of the current defun. |
| 851 | With ARG, move backward multiple defuns. Negative ARG means | 963 | With ARG, move backward multiple defuns. Negative ARG means |
| 852 | move forward." | 964 | move forward." |
| 853 | (interactive "p") | 965 | (interactive "p") |
| 854 | (and (re-search-backward (concat "^\\s *" ruby-defun-beg-re "\\_>") | 966 | (let (case-fold-search) |
| 855 | nil t (or arg 1)) | 967 | (and (re-search-backward (concat "^\\s *" ruby-defun-beg-re "\\_>") |
| 856 | (beginning-of-line))) | 968 | nil t (or arg 1)) |
| 857 | 969 | (beginning-of-line)))) | |
| 858 | (defun ruby-end-of-defun (&optional arg) | 970 | |
| 859 | "Move forward to the end of the current top-level defun. | 971 | (defun ruby-end-of-defun () |
| 860 | With ARG, move forward multiple defuns. Negative ARG means | 972 | "Move point to the end of the current defun. |
| 861 | move backward." | 973 | The defun begins at or after the point. This function is called |
| 974 | by `end-of-defun'." | ||
| 862 | (interactive "p") | 975 | (interactive "p") |
| 863 | (ruby-forward-sexp) | 976 | (ruby-forward-sexp) |
| 864 | (when (looking-back (concat "^\\s *" ruby-block-end-re)) | 977 | (let (case-fold-search) |
| 865 | (forward-line 1))) | 978 | (when (looking-back (concat "^\\s *" ruby-block-end-re)) |
| 979 | (forward-line 1)))) | ||
| 866 | 980 | ||
| 867 | (defun ruby-beginning-of-indent () | 981 | (defun ruby-beginning-of-indent () |
| 868 | "Backtrack to a line which can be used as a reference for | 982 | "Backtrack to a line which can be used as a reference for |
| @@ -881,6 +995,7 @@ current block, a sibling block, or an outer block. Do that (abs N) times." | |||
| 881 | (depth (or (nth 2 (ruby-parse-region (line-beginning-position) | 995 | (depth (or (nth 2 (ruby-parse-region (line-beginning-position) |
| 882 | (line-end-position))) | 996 | (line-end-position))) |
| 883 | 0)) | 997 | 0)) |
| 998 | case-fold-search | ||
| 884 | down done) | 999 | down done) |
| 885 | (when (< (* depth signum) 0) | 1000 | (when (< (* depth signum) 0) |
| 886 | ;; Moving end -> end or beginning -> beginning. | 1001 | ;; Moving end -> end or beginning -> beginning. |
| @@ -1232,6 +1347,9 @@ If the result is do-end block, it will always be multiline." | |||
| 1232 | (declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit)) | 1347 | (declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit)) |
| 1233 | (declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit)) | 1348 | (declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit)) |
| 1234 | (declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit)) | 1349 | (declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit)) |
| 1350 | ;; Unusual code layout confuses the byte-compiler. | ||
| 1351 | (declare-function ruby-syntax-propertize-expansion "ruby-mode" ()) | ||
| 1352 | (declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state)) | ||
| 1235 | 1353 | ||
| 1236 | (if (eval-when-compile (fboundp #'syntax-propertize-rules)) | 1354 | (if (eval-when-compile (fboundp #'syntax-propertize-rules)) |
| 1237 | ;; New code that works independently from font-lock. | 1355 | ;; New code that works independently from font-lock. |
| @@ -1245,54 +1363,70 @@ If the result is do-end block, it will always be multiline." | |||
| 1245 | '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match" | 1363 | '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match" |
| 1246 | "assert_match" "Given" "Then" "When") | 1364 | "assert_match" "Given" "Then" "When") |
| 1247 | "Methods that can take regexp as the first argument. | 1365 | "Methods that can take regexp as the first argument. |
| 1248 | It will be properly highlighted even when the call omits parens.")) | 1366 | It will be properly highlighted even when the call omits parens.") |
| 1367 | |||
| 1368 | (defvar ruby-syntax-before-regexp-re | ||
| 1369 | (concat | ||
| 1370 | ;; Special tokens that can't be followed by a division operator. | ||
| 1371 | "\\(^\\|[[=(,~?:;<>]" | ||
| 1372 | ;; Control flow keywords and operators following bol or whitespace. | ||
| 1373 | "\\|\\(?:^\\|\\s \\)" | ||
| 1374 | (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and" | ||
| 1375 | "or" "not" "&&" "||")) | ||
| 1376 | ;; Method name from the list. | ||
| 1377 | "\\|\\_<" | ||
| 1378 | (regexp-opt ruby-syntax-methods-before-regexp) | ||
| 1379 | "\\)\\s *") | ||
| 1380 | "Regexp to match text that can be followed by a regular expression.")) | ||
| 1249 | 1381 | ||
| 1250 | (defun ruby-syntax-propertize-function (start end) | 1382 | (defun ruby-syntax-propertize-function (start end) |
| 1251 | "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." | 1383 | "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." |
| 1252 | (goto-char start) | 1384 | (let (case-fold-search) |
| 1253 | (ruby-syntax-propertize-heredoc end) | 1385 | (goto-char start) |
| 1254 | (ruby-syntax-enclosing-percent-literal end) | 1386 | (remove-text-properties start end '(ruby-expansion-match-data)) |
| 1255 | (funcall | 1387 | (ruby-syntax-propertize-heredoc end) |
| 1256 | (syntax-propertize-rules | 1388 | (ruby-syntax-enclosing-percent-literal end) |
| 1257 | ;; $' $" $` .... are variables. | 1389 | (funcall |
| 1258 | ;; ?' ?" ?` are ascii codes. | 1390 | (syntax-propertize-rules |
| 1259 | ("\\([?$]\\)[#\"'`]" | 1391 | ;; $' $" $` .... are variables. |
| 1260 | (1 (unless (save-excursion | 1392 | ;; ?' ?" ?` are ascii codes. |
| 1261 | ;; Not within a string. | 1393 | ("\\([?$]\\)[#\"'`]" |
| 1262 | (nth 3 (syntax-ppss (match-beginning 0)))) | 1394 | (1 (unless (save-excursion |
| 1263 | (string-to-syntax "\\")))) | 1395 | ;; Not within a string. |
| 1264 | ;; Regexps: regexps are distinguished from division because | 1396 | (nth 3 (syntax-ppss (match-beginning 0)))) |
| 1265 | ;; of the keyword, symbol, or method name before them. | 1397 | (string-to-syntax "\\")))) |
| 1266 | ((concat | 1398 | ;; Regular expressions. Start with matching unescaped slash. |
| 1267 | ;; Special tokens that can't be followed by a division operator. | 1399 | ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)" |
| 1268 | "\\(^\\|[[=(,~?:;<>]" | 1400 | (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1))))) |
| 1269 | ;; Control flow keywords and operators following bol or whitespace. | 1401 | (when (or |
| 1270 | "\\|\\(?:^\\|\\s \\)" | 1402 | ;; Beginning of a regexp. |
| 1271 | (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and" | 1403 | (and (null (nth 8 state)) |
| 1272 | "or" "not" "&&" "||")) | 1404 | (save-excursion |
| 1273 | ;; Method name from the list. | 1405 | (forward-char -1) |
| 1274 | "\\|\\_<" | 1406 | (looking-back ruby-syntax-before-regexp-re |
| 1275 | (regexp-opt ruby-syntax-methods-before-regexp) | 1407 | (point-at-bol)))) |
| 1276 | "\\)\\s *" | 1408 | ;; End of regexp. We don't match the whole |
| 1277 | ;; The regular expression itself. | 1409 | ;; regexp at once because it can have |
| 1278 | "\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)") | 1410 | ;; string interpolation inside, or span |
| 1279 | (3 (unless (nth 3 (syntax-ppss (match-beginning 2))) | 1411 | ;; several lines. |
| 1280 | (put-text-property (match-beginning 2) (match-end 2) | 1412 | (eq ?/ (nth 3 state))) |
| 1281 | 'syntax-table (string-to-syntax "\"/")) | 1413 | (string-to-syntax "\"/"))))) |
| 1282 | (string-to-syntax "\"/")))) | 1414 | ;; Expression expansions in strings. We're handling them |
| 1283 | ("^=en\\(d\\)\\_>" (1 "!")) | 1415 | ;; here, so that the regexp rule never matches inside them. |
| 1284 | ("^\\(=\\)begin\\_>" (1 "!")) | 1416 | (ruby-expression-expansion-re |
| 1285 | ;; Handle here documents. | 1417 | (0 (ignore (ruby-syntax-propertize-expansion)))) |
| 1286 | ((concat ruby-here-doc-beg-re ".*\\(\n\\)") | 1418 | ("^=en\\(d\\)\\_>" (1 "!")) |
| 1287 | (7 (unless (ruby-singleton-class-p (match-beginning 0)) | 1419 | ("^\\(=\\)begin\\_>" (1 "!")) |
| 1288 | (put-text-property (match-beginning 7) (match-end 7) | 1420 | ;; Handle here documents. |
| 1289 | 'syntax-table (string-to-syntax "\"")) | 1421 | ((concat ruby-here-doc-beg-re ".*\\(\n\\)") |
| 1290 | (ruby-syntax-propertize-heredoc end)))) | 1422 | (7 (unless (ruby-singleton-class-p (match-beginning 0)) |
| 1291 | ;; Handle percent literals: %w(), %q{}, etc. | 1423 | (put-text-property (match-beginning 7) (match-end 7) |
| 1292 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) | 1424 | 'syntax-table (string-to-syntax "\"")) |
| 1293 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) | 1425 | (ruby-syntax-propertize-heredoc end)))) |
| 1294 | (point) end) | 1426 | ;; Handle percent literals: %w(), %q{}, etc. |
| 1295 | (ruby-syntax-propertize-expansions start end)) | 1427 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) |
| 1428 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) | ||
| 1429 | (point) end))) | ||
| 1296 | 1430 | ||
| 1297 | (defun ruby-syntax-propertize-heredoc (limit) | 1431 | (defun ruby-syntax-propertize-heredoc (limit) |
| 1298 | (let ((ppss (syntax-ppss)) | 1432 | (let ((ppss (syntax-ppss)) |
| @@ -1305,7 +1439,7 @@ It will be properly highlighted even when the call omits parens.")) | |||
| 1305 | (line-end-position) t) | 1439 | (line-end-position) t) |
| 1306 | (unless (ruby-singleton-class-p (match-beginning 0)) | 1440 | (unless (ruby-singleton-class-p (match-beginning 0)) |
| 1307 | (push (concat (ruby-here-doc-end-match) "\n") res)))) | 1441 | (push (concat (ruby-here-doc-end-match) "\n") res)))) |
| 1308 | (let ((start (point))) | 1442 | (save-excursion |
| 1309 | ;; With multiple openers on the same line, we don't know in which | 1443 | ;; With multiple openers on the same line, we don't know in which |
| 1310 | ;; part `start' is, so we have to go back to the beginning. | 1444 | ;; part `start' is, so we have to go back to the beginning. |
| 1311 | (when (cdr res) | 1445 | (when (cdr res) |
| @@ -1315,9 +1449,9 @@ It will be properly highlighted even when the call omits parens.")) | |||
| 1315 | (if (null res) | 1449 | (if (null res) |
| 1316 | (put-text-property (1- (point)) (point) | 1450 | (put-text-property (1- (point)) (point) |
| 1317 | 'syntax-table (string-to-syntax "\"")))) | 1451 | 'syntax-table (string-to-syntax "\"")))) |
| 1318 | ;; Make extra sure we don't move back, lest we could fall into an | 1452 | ;; End up at bol following the heredoc openers. |
| 1319 | ;; inf-loop. | 1453 | ;; Propertize expression expansions from this point forward. |
| 1320 | (if (< (point) start) (goto-char start)))))) | 1454 | )))) |
| 1321 | 1455 | ||
| 1322 | (defun ruby-syntax-enclosing-percent-literal (limit) | 1456 | (defun ruby-syntax-enclosing-percent-literal (limit) |
| 1323 | (let ((state (syntax-ppss)) | 1457 | (let ((state (syntax-ppss)) |
| @@ -1338,44 +1472,59 @@ It will be properly highlighted even when the call omits parens.")) | |||
| 1338 | (cl (or (cdr (aref (syntax-table) op)) | 1472 | (cl (or (cdr (aref (syntax-table) op)) |
| 1339 | (cdr (assoc op '((?< . ?>)))))) | 1473 | (cdr (assoc op '((?< . ?>)))))) |
| 1340 | parse-sexp-lookup-properties) | 1474 | parse-sexp-lookup-properties) |
| 1341 | (condition-case nil | 1475 | (save-excursion |
| 1342 | (progn | 1476 | (condition-case nil |
| 1343 | (if cl ; Paired delimiters. | 1477 | (progn |
| 1344 | ;; Delimiter pairs of the same kind can be nested | 1478 | (if cl ; Paired delimiters. |
| 1345 | ;; inside the literal, as long as they are balanced. | 1479 | ;; Delimiter pairs of the same kind can be nested |
| 1346 | ;; Create syntax table that ignores other characters. | 1480 | ;; inside the literal, as long as they are balanced. |
| 1347 | (with-syntax-table (make-char-table 'syntax-table nil) | 1481 | ;; Create syntax table that ignores other characters. |
| 1348 | (modify-syntax-entry op (concat "(" (char-to-string cl))) | 1482 | (with-syntax-table (make-char-table 'syntax-table nil) |
| 1349 | (modify-syntax-entry cl (concat ")" ops)) | 1483 | (modify-syntax-entry op (concat "(" (char-to-string cl))) |
| 1350 | (modify-syntax-entry ?\\ "\\") | 1484 | (modify-syntax-entry cl (concat ")" ops)) |
| 1351 | (save-restriction | 1485 | (modify-syntax-entry ?\\ "\\") |
| 1352 | (narrow-to-region (point) limit) | 1486 | (save-restriction |
| 1353 | (forward-list))) ; skip to the paired character | 1487 | (narrow-to-region (point) limit) |
| 1354 | ;; Single character delimiter. | 1488 | (forward-list))) ; skip to the paired character |
| 1355 | (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*" | 1489 | ;; Single character delimiter. |
| 1356 | (regexp-quote ops)) limit nil)) | 1490 | (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*" |
| 1357 | ;; Found the closing delimiter. | 1491 | (regexp-quote ops)) limit nil)) |
| 1358 | (put-text-property (1- (point)) (point) 'syntax-table | 1492 | ;; Found the closing delimiter. |
| 1359 | (string-to-syntax "|"))) | 1493 | (put-text-property (1- (point)) (point) 'syntax-table |
| 1360 | ;; Unclosed literal, leave the following text unpropertized. | 1494 | (string-to-syntax "|"))) |
| 1361 | ((scan-error search-failed) (goto-char limit)))))) | 1495 | ;; Unclosed literal, do nothing. |
| 1496 | ((scan-error search-failed))))))) | ||
| 1497 | |||
| 1498 | (defun ruby-syntax-propertize-expansion () | ||
| 1499 | ;; Save the match data to a text property, for font-locking later. | ||
| 1500 | ;; Set the syntax of all double quotes and backticks to punctuation. | ||
| 1501 | (let* ((beg (match-beginning 2)) | ||
| 1502 | (end (match-end 2)) | ||
| 1503 | (state (and beg (save-excursion (syntax-ppss beg))))) | ||
| 1504 | (when (ruby-syntax-expansion-allowed-p state) | ||
| 1505 | (put-text-property beg (1+ beg) 'ruby-expansion-match-data | ||
| 1506 | (match-data)) | ||
| 1507 | (goto-char beg) | ||
| 1508 | (while (re-search-forward "[\"`]" end 'move) | ||
| 1509 | (put-text-property (match-beginning 0) (match-end 0) | ||
| 1510 | 'syntax-table (string-to-syntax ".")))))) | ||
| 1511 | |||
| 1512 | (defun ruby-syntax-expansion-allowed-p (parse-state) | ||
| 1513 | "Return non-nil if expression expansion is allowed." | ||
| 1514 | (let ((term (nth 3 parse-state))) | ||
| 1515 | (cond | ||
| 1516 | ((memq term '(?\" ?` ?\n ?/))) | ||
| 1517 | ((eq term t) | ||
| 1518 | (save-match-data | ||
| 1519 | (save-excursion | ||
| 1520 | (goto-char (nth 8 parse-state)) | ||
| 1521 | (looking-at "%\\(?:[QWrx]\\|\\W\\)"))))))) | ||
| 1362 | 1522 | ||
| 1363 | (defun ruby-syntax-propertize-expansions (start end) | 1523 | (defun ruby-syntax-propertize-expansions (start end) |
| 1364 | (remove-text-properties start end '(ruby-expansion-match-data)) | 1524 | (save-excursion |
| 1365 | (goto-char start) | 1525 | (goto-char start) |
| 1366 | ;; Find all expression expansions and | 1526 | (while (re-search-forward ruby-expression-expansion-re end 'move) |
| 1367 | ;; - save the match data to a text property, for font-locking later, | 1527 | (ruby-syntax-propertize-expansion)))) |
| 1368 | ;; - set the syntax of all double quotes and backticks to punctuation. | ||
| 1369 | (while (re-search-forward ruby-expression-expansion-re end 'move) | ||
| 1370 | (let ((beg (match-beginning 2)) | ||
| 1371 | (end (match-end 2))) | ||
| 1372 | (when (and beg (save-excursion (nth 3 (syntax-ppss beg)))) | ||
| 1373 | (put-text-property beg (1+ beg) 'ruby-expansion-match-data | ||
| 1374 | (match-data)) | ||
| 1375 | (goto-char beg) | ||
| 1376 | (while (re-search-forward "[\"`]" end 'move) | ||
| 1377 | (put-text-property (match-beginning 0) (match-end 0) | ||
| 1378 | 'syntax-table (string-to-syntax "."))))))) | ||
| 1379 | ) | 1528 | ) |
| 1380 | 1529 | ||
| 1381 | ;; For Emacsen where syntax-propertize-rules is not (yet) available, | 1530 | ;; For Emacsen where syntax-propertize-rules is not (yet) available, |