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.el351
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.
851With ARG, move backward multiple defuns. Negative ARG means 963With ARG, move backward multiple defuns. Negative ARG means
852move forward." 964move 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 ()
860With ARG, move forward multiple defuns. Negative ARG means 972 "Move point to the end of the current defun.
861move backward." 973The defun begins at or after the point. This function is called
974by `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.
1248It will be properly highlighted even when the call omits parens.")) 1366It 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,