aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Gutov2013-11-02 05:10:10 +0400
committerDmitry Gutov2013-11-02 05:10:10 +0400
commit7ffd37219b311035fd346a126d7799cb53c6c73d (patch)
tree019bd2432af865a67831367d25fda06f84e94a19
parenta3996a2eba1a85e33da320f7bcec0e714ea1d6d6 (diff)
downloademacs-7ffd37219b311035fd346a126d7799cb53c6c73d.tar.gz
emacs-7ffd37219b311035fd346a126d7799cb53c6c73d.zip
* lisp/progmodes/ruby-mode.el Use `syntax-propertize-function'
unconditionally. Remove now unnecessary forward declarations. Remove XEmacs-specific setup. (ruby-here-doc-end-re, ruby-here-doc-beg-match) (ruby-font-lock-syntactic-keywords) (ruby-comment-beg-syntax, ruby-in-here-doc-p) (ruby-here-doc-find-end, ruby-here-doc-beg-syntax) (ruby-here-doc-end-syntax): Remove. (ruby-mode): Don't check whether `syntax-propertize-rules' is defined as function.
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/progmodes/ruby-mode.el521
2 files changed, 185 insertions, 349 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index dc8cc973423..3de7afba477 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,16 @@
12013-11-02 Dmitry Gutov <dgutov@yandex.ru>
2
3 * progmodes/ruby-mode.el Use `syntax-propertize-function'
4 unconditionally. Remove now unnecessary forward declarations.
5 Remove XEmacs-specific setup.
6 (ruby-here-doc-end-re, ruby-here-doc-beg-match)
7 (ruby-font-lock-syntactic-keywords)
8 (ruby-comment-beg-syntax, ruby-in-here-doc-p)
9 (ruby-here-doc-find-end, ruby-here-doc-beg-syntax)
10 (ruby-here-doc-end-syntax): Remove.
11 (ruby-mode): Don't check whether `syntax-propertize-rules' is
12 defined as function.
13
12013-11-02 Bozhidar Batsov <bozhidar@batsov.com> 142013-11-02 Bozhidar Batsov <bozhidar@batsov.com>
2 15
3 * progmodes/ruby-mode.el (ruby-mode-variables, ruby-mode): Use `setq-local'. 16 * progmodes/ruby-mode.el (ruby-mode-variables, ruby-mode): Use `setq-local'.
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index c8d7169ca58..75c59ebe1fd 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -1515,349 +1515,182 @@ If the result is do-end block, it will always be multiline."
1515 (ruby-do-end-to-brace beg end))) 1515 (ruby-do-end-to-brace beg end)))
1516 (goto-char start)))) 1516 (goto-char start))))
1517 1517
1518(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit)) 1518(eval-and-compile
1519(declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit)) 1519 (defconst ruby-percent-literal-beg-re
1520(declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit)) 1520 "\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
1521;; Unusual code layout confuses the byte-compiler. 1521 "Regexp to match the beginning of percent literal.")
1522(declare-function ruby-syntax-propertize-expansion "ruby-mode" ()) 1522
1523(declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state)) 1523 (defconst ruby-syntax-methods-before-regexp
1524(declare-function ruby-syntax-propertize-function "ruby-mode" (start end)) 1524 '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
1525 1525 "assert_match" "Given" "Then" "When")
1526(if (eval-when-compile (fboundp #'syntax-propertize-rules)) 1526 "Methods that can take regexp as the first argument.
1527 ;; New code that works independently from font-lock.
1528 (progn
1529 (eval-and-compile
1530 (defconst ruby-percent-literal-beg-re
1531 "\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
1532 "Regexp to match the beginning of percent literal.")
1533
1534 (defconst ruby-syntax-methods-before-regexp
1535 '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
1536 "assert_match" "Given" "Then" "When")
1537 "Methods that can take regexp as the first argument.
1538It will be properly highlighted even when the call omits parens.") 1527It will be properly highlighted even when the call omits parens.")
1539 1528
1540 (defvar ruby-syntax-before-regexp-re 1529 (defvar ruby-syntax-before-regexp-re
1541 (concat 1530 (concat
1542 ;; Special tokens that can't be followed by a division operator. 1531 ;; Special tokens that can't be followed by a division operator.
1543 "\\(^\\|[[=(,~;<>]" 1532 "\\(^\\|[[=(,~;<>]"
1544 ;; Distinguish ternary operator tokens. 1533 ;; Distinguish ternary operator tokens.
1545 ;; FIXME: They don't really have to be separated with spaces. 1534 ;; FIXME: They don't really have to be separated with spaces.
1546 "\\|[?:] " 1535 "\\|[?:] "
1547 ;; Control flow keywords and operators following bol or whitespace. 1536 ;; Control flow keywords and operators following bol or whitespace.
1548 "\\|\\(?:^\\|\\s \\)" 1537 "\\|\\(?:^\\|\\s \\)"
1549 (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and" 1538 (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
1550 "or" "not" "&&" "||")) 1539 "or" "not" "&&" "||"))
1551 ;; Method name from the list. 1540 ;; Method name from the list.
1552 "\\|\\_<" 1541 "\\|\\_<"
1553 (regexp-opt ruby-syntax-methods-before-regexp) 1542 (regexp-opt ruby-syntax-methods-before-regexp)
1554 "\\)\\s *") 1543 "\\)\\s *")
1555 "Regexp to match text that can be followed by a regular expression.")) 1544 "Regexp to match text that can be followed by a regular expression."))
1556 1545
1557 (defun ruby-syntax-propertize-function (start end) 1546(defun ruby-syntax-propertize-function (start end)
1558 "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." 1547 "Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
1559 (let (case-fold-search) 1548 (let (case-fold-search)
1560 (goto-char start) 1549 (goto-char start)
1561 (remove-text-properties start end '(ruby-expansion-match-data)) 1550 (remove-text-properties start end '(ruby-expansion-match-data))
1562 (ruby-syntax-propertize-heredoc end) 1551 (ruby-syntax-propertize-heredoc end)
1563 (ruby-syntax-enclosing-percent-literal end) 1552 (ruby-syntax-enclosing-percent-literal end)
1564 (funcall 1553 (funcall
1565 (syntax-propertize-rules 1554 (syntax-propertize-rules
1566 ;; $' $" $` .... are variables. 1555 ;; $' $" $` .... are variables.
1567 ;; ?' ?" ?` are character literals (one-char strings in 1.9+). 1556 ;; ?' ?" ?` are character literals (one-char strings in 1.9+).
1568 ("\\([?$]\\)[#\"'`]" 1557 ("\\([?$]\\)[#\"'`]"
1569 (1 (unless (save-excursion 1558 (1 (unless (save-excursion
1570 ;; Not within a string. 1559 ;; Not within a string.
1571 (nth 3 (syntax-ppss (match-beginning 0)))) 1560 (nth 3 (syntax-ppss (match-beginning 0))))
1572 (string-to-syntax "\\")))) 1561 (string-to-syntax "\\"))))
1573 ;; Regular expressions. Start with matching unescaped slash. 1562 ;; Regular expressions. Start with matching unescaped slash.
1574 ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)" 1563 ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
1575 (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1))))) 1564 (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
1576 (when (or 1565 (when (or
1577 ;; Beginning of a regexp. 1566 ;; Beginning of a regexp.
1578 (and (null (nth 8 state)) 1567 (and (null (nth 8 state))
1579 (save-excursion 1568 (save-excursion
1580 (forward-char -1) 1569 (forward-char -1)
1581 (looking-back ruby-syntax-before-regexp-re 1570 (looking-back ruby-syntax-before-regexp-re
1582 (point-at-bol)))) 1571 (point-at-bol))))
1583 ;; End of regexp. We don't match the whole 1572 ;; End of regexp. We don't match the whole
1584 ;; regexp at once because it can have 1573 ;; regexp at once because it can have
1585 ;; string interpolation inside, or span 1574 ;; string interpolation inside, or span
1586 ;; several lines. 1575 ;; several lines.
1587 (eq ?/ (nth 3 state))) 1576 (eq ?/ (nth 3 state)))
1588 (string-to-syntax "\"/"))))) 1577 (string-to-syntax "\"/")))))
1589 ;; Expression expansions in strings. We're handling them 1578 ;; Expression expansions in strings. We're handling them
1590 ;; here, so that the regexp rule never matches inside them. 1579 ;; here, so that the regexp rule never matches inside them.
1591 (ruby-expression-expansion-re 1580 (ruby-expression-expansion-re
1592 (0 (ignore (ruby-syntax-propertize-expansion)))) 1581 (0 (ignore (ruby-syntax-propertize-expansion))))
1593 ("^=en\\(d\\)\\_>" (1 "!")) 1582 ("^=en\\(d\\)\\_>" (1 "!"))
1594 ("^\\(=\\)begin\\_>" (1 "!")) 1583 ("^\\(=\\)begin\\_>" (1 "!"))
1595 ;; Handle here documents. 1584 ;; Handle here documents.
1596 ((concat ruby-here-doc-beg-re ".*\\(\n\\)") 1585 ((concat ruby-here-doc-beg-re ".*\\(\n\\)")
1597 (7 (unless (or (nth 8 (save-excursion 1586 (7 (unless (or (nth 8 (save-excursion
1598 (syntax-ppss (match-beginning 0)))) 1587 (syntax-ppss (match-beginning 0))))
1599 (ruby-singleton-class-p (match-beginning 0))) 1588 (ruby-singleton-class-p (match-beginning 0)))
1600 (put-text-property (match-beginning 7) (match-end 7) 1589 (put-text-property (match-beginning 7) (match-end 7)
1601 'syntax-table (string-to-syntax "\"")) 1590 'syntax-table (string-to-syntax "\""))
1602 (ruby-syntax-propertize-heredoc end)))) 1591 (ruby-syntax-propertize-heredoc end))))
1603 ;; Handle percent literals: %w(), %q{}, etc. 1592 ;; Handle percent literals: %w(), %q{}, etc.
1604 ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) 1593 ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
1605 (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) 1594 (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
1606 (point) end))) 1595 (point) end)))
1607 1596
1608 (defun ruby-syntax-propertize-heredoc (limit) 1597(defun ruby-syntax-propertize-heredoc (limit)
1609 (let ((ppss (syntax-ppss)) 1598 (let ((ppss (syntax-ppss))
1610 (res '())) 1599 (res '()))
1611 (when (eq ?\n (nth 3 ppss)) 1600 (when (eq ?\n (nth 3 ppss))
1612 (save-excursion 1601 (save-excursion
1613 (goto-char (nth 8 ppss)) 1602 (goto-char (nth 8 ppss))
1614 (beginning-of-line)
1615 (while (re-search-forward ruby-here-doc-beg-re
1616 (line-end-position) t)
1617 (unless (ruby-singleton-class-p (match-beginning 0))
1618 (push (concat (ruby-here-doc-end-match) "\n") res))))
1619 (save-excursion
1620 ;; With multiple openers on the same line, we don't know in which
1621 ;; part `start' is, so we have to go back to the beginning.
1622 (when (cdr res)
1623 (goto-char (nth 8 ppss))
1624 (setq res (nreverse res)))
1625 (while (and res (re-search-forward (pop res) limit 'move))
1626 (if (null res)
1627 (put-text-property (1- (point)) (point)
1628 'syntax-table (string-to-syntax "\""))))
1629 ;; End up at bol following the heredoc openers.
1630 ;; Propertize expression expansions from this point forward.
1631 ))))
1632
1633 (defun ruby-syntax-enclosing-percent-literal (limit)
1634 (let ((state (syntax-ppss))
1635 (start (point)))
1636 ;; When already inside percent literal, re-propertize it.
1637 (when (eq t (nth 3 state))
1638 (goto-char (nth 8 state))
1639 (when (looking-at ruby-percent-literal-beg-re)
1640 (ruby-syntax-propertize-percent-literal limit))
1641 (when (< (point) start) (goto-char start)))))
1642
1643 (defun ruby-syntax-propertize-percent-literal (limit)
1644 (goto-char (match-beginning 2))
1645 ;; Not inside a simple string or comment.
1646 (when (eq t (nth 3 (syntax-ppss)))
1647 (let* ((op (char-after))
1648 (ops (char-to-string op))
1649 (cl (or (cdr (aref (syntax-table) op))
1650 (cdr (assoc op '((?< . ?>))))))
1651 parse-sexp-lookup-properties)
1652 (save-excursion
1653 (condition-case nil
1654 (progn
1655 (if cl ; Paired delimiters.
1656 ;; Delimiter pairs of the same kind can be nested
1657 ;; inside the literal, as long as they are balanced.
1658 ;; Create syntax table that ignores other characters.
1659 (with-syntax-table (make-char-table 'syntax-table nil)
1660 (modify-syntax-entry op (concat "(" (char-to-string cl)))
1661 (modify-syntax-entry cl (concat ")" ops))
1662 (modify-syntax-entry ?\\ "\\")
1663 (save-restriction
1664 (narrow-to-region (point) limit)
1665 (forward-list))) ; skip to the paired character
1666 ;; Single character delimiter.
1667 (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
1668 (regexp-quote ops)) limit nil))
1669 ;; Found the closing delimiter.
1670 (put-text-property (1- (point)) (point) 'syntax-table
1671 (string-to-syntax "|")))
1672 ;; Unclosed literal, do nothing.
1673 ((scan-error search-failed)))))))
1674
1675 (defun ruby-syntax-propertize-expansion ()
1676 ;; Save the match data to a text property, for font-locking later.
1677 ;; Set the syntax of all double quotes and backticks to punctuation.
1678 (let* ((beg (match-beginning 2))
1679 (end (match-end 2))
1680 (state (and beg (save-excursion (syntax-ppss beg)))))
1681 (when (ruby-syntax-expansion-allowed-p state)
1682 (put-text-property beg (1+ beg) 'ruby-expansion-match-data
1683 (match-data))
1684 (goto-char beg)
1685 (while (re-search-forward "[\"`]" end 'move)
1686 (put-text-property (match-beginning 0) (match-end 0)
1687 'syntax-table (string-to-syntax "."))))))
1688
1689 (defun ruby-syntax-expansion-allowed-p (parse-state)
1690 "Return non-nil if expression expansion is allowed."
1691 (let ((term (nth 3 parse-state)))
1692 (cond
1693 ((memq term '(?\" ?` ?\n ?/)))
1694 ((eq term t)
1695 (save-match-data
1696 (save-excursion
1697 (goto-char (nth 8 parse-state))
1698 (looking-at "%\\(?:[QWrxI]\\|\\W\\)")))))))
1699
1700 (defun ruby-syntax-propertize-expansions (start end)
1701 (save-excursion
1702 (goto-char start)
1703 (while (re-search-forward ruby-expression-expansion-re end 'move)
1704 (ruby-syntax-propertize-expansion))))
1705 )
1706
1707 ;; For Emacsen where syntax-propertize-rules is not (yet) available,
1708 ;; fallback on the old font-lock-syntactic-keywords stuff.
1709
1710 (defconst ruby-here-doc-end-re
1711 "^\\([ \t]+\\)?\\(.*\\)\\(\n\\)"
1712 "Regexp to match the end of heredocs.
1713
1714This will actually match any line with one or more characters.
1715It's useful in that it divides up the match string so that
1716`ruby-here-doc-beg-match' can search for the beginning of the heredoc.")
1717
1718 (defun ruby-here-doc-beg-match ()
1719 "Return a regexp to find the beginning of a heredoc.
1720
1721This should only be called after matching against `ruby-here-doc-end-re'."
1722 (let ((contents (concat
1723 (regexp-quote (concat (match-string 2) (match-string 3)))
1724 (if (string= (match-string 3) "_") "\\B" "\\b"))))
1725 (concat "<<"
1726 (let ((match (match-string 1)))
1727 (if (and match (> (length match) 0))
1728 (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)"
1729 (match-string 1) "\\)"
1730 contents "\\(\\1\\|\\2\\)")
1731 (concat "-?\\([\"']\\|\\)" contents "\\1"))))))
1732
1733 (defconst ruby-font-lock-syntactic-keywords
1734 `(
1735 ;; the last $', $", $` in the respective string is not variable
1736 ;; the last ?', ?", ?` in the respective string is not ascii code
1737 ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
1738 (2 (7 . nil))
1739 (4 (7 . nil)))
1740 ;; $' $" $` .... are variables
1741 ;; ?' ?" ?` are ascii codes
1742 ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil))
1743 ;; regexps
1744 ("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
1745 (4 (7 . ?/))
1746 (6 (7 . ?/)))
1747 ("^=en\\(d\\)\\_>" 1 "!")
1748 ;; Percent literal.
1749 ("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
1750 (3 "\"")
1751 (5 "\""))
1752 ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax))
1753 ;; Currently, the following case is highlighted incorrectly:
1754 ;;
1755 ;; <<FOO
1756 ;; FOO
1757 ;; <<BAR
1758 ;; <<BAZ
1759 ;; BAZ
1760 ;; BAR
1761 ;;
1762 ;; This is because all here-doc beginnings are highlighted before any endings,
1763 ;; so although <<BAR is properly marked as a beginning, when we get to <<BAZ
1764 ;; it thinks <<BAR is part of a string so it's marked as well.
1765 ;;
1766 ;; This may be fixable by modifying ruby-in-here-doc-p to use
1767 ;; ruby-in-non-here-doc-string-p rather than syntax-ppss-context,
1768 ;; but I don't want to try that until we've got unit tests set up
1769 ;; to make sure I don't break anything else.
1770 (,(concat ruby-here-doc-beg-re ".*\\(\n\\)")
1771 ,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re))
1772 (ruby-here-doc-beg-syntax))
1773 (,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax)))
1774 "Syntactic keywords for Ruby mode. See `font-lock-syntactic-keywords'.")
1775
1776 (defun ruby-comment-beg-syntax ()
1777 "Return the syntax cell for a the first character of a =begin.
1778See the definition of `ruby-font-lock-syntactic-keywords'.
1779
1780This returns a comment-delimiter cell as long as the =begin
1781isn't in a string or another comment."
1782 (when (not (nth 3 (syntax-ppss)))
1783 (string-to-syntax "!")))
1784
1785 (defun ruby-in-here-doc-p ()
1786 "Return whether or not the point is in a heredoc."
1787 (save-excursion
1788 (let ((old-point (point)) (case-fold-search nil))
1789 (beginning-of-line) 1603 (beginning-of-line)
1790 (catch 'found-beg 1604 (while (re-search-forward ruby-here-doc-beg-re
1791 (while (and (re-search-backward ruby-here-doc-beg-re nil t) 1605 (line-end-position) t)
1792 (not (ruby-singleton-class-p))) 1606 (unless (ruby-singleton-class-p (match-beginning 0))
1793 (if (not (or (ruby-in-ppss-context-p 'anything) 1607 (push (concat (ruby-here-doc-end-match) "\n") res))))
1794 (ruby-here-doc-find-end old-point))) 1608 (save-excursion
1795 (throw 'found-beg t))))))) 1609 ;; With multiple openers on the same line, we don't know in which
1796 1610 ;; part `start' is, so we have to go back to the beginning.
1797 (defun ruby-here-doc-find-end (&optional limit) 1611 (when (cdr res)
1798 "Expects the point to be on a line with one or more heredoc openers. 1612 (goto-char (nth 8 ppss))
1799Returns the buffer position at which all heredocs on the line 1613 (setq res (nreverse res)))
1800are terminated, or nil if they aren't terminated before the 1614 (while (and res (re-search-forward (pop res) limit 'move))
1801buffer position `limit' or the end of the buffer." 1615 (if (null res)
1802 (save-excursion 1616 (put-text-property (1- (point)) (point)
1803 (beginning-of-line) 1617 'syntax-table (string-to-syntax "\""))))
1804 (catch 'done 1618 ;; End up at bol following the heredoc openers.
1805 (let ((eol (point-at-eol)) 1619 ;; Propertize expression expansions from this point forward.
1806 (case-fold-search nil) 1620 ))))
1807 ;; Fake match data such that (match-end 0) is at eol 1621
1808 (end-match-data (progn (looking-at ".*$") (match-data))) 1622(defun ruby-syntax-enclosing-percent-literal (limit)
1809 beg-match-data end-re) 1623 (let ((state (syntax-ppss))
1810 (while (re-search-forward ruby-here-doc-beg-re eol t) 1624 (start (point)))
1811 (setq beg-match-data (match-data)) 1625 ;; When already inside percent literal, re-propertize it.
1812 (setq end-re (ruby-here-doc-end-match)) 1626 (when (eq t (nth 3 state))
1813 1627 (goto-char (nth 8 state))
1814 (set-match-data end-match-data) 1628 (when (looking-at ruby-percent-literal-beg-re)
1815 (goto-char (match-end 0)) 1629 (ruby-syntax-propertize-percent-literal limit))
1816 (unless (re-search-forward end-re limit t) (throw 'done nil)) 1630 (when (< (point) start) (goto-char start)))))
1817 (setq end-match-data (match-data)) 1631
1818 1632(defun ruby-syntax-propertize-percent-literal (limit)
1819 (set-match-data beg-match-data) 1633 (goto-char (match-beginning 2))
1820 (goto-char (match-end 0))) 1634 ;; Not inside a simple string or comment.
1821 (set-match-data end-match-data) 1635 (when (eq t (nth 3 (syntax-ppss)))
1822 (goto-char (match-end 0)) 1636 (let* ((op (char-after))
1823 (point))))) 1637 (ops (char-to-string op))
1824 1638 (cl (or (cdr (aref (syntax-table) op))
1825 (defun ruby-here-doc-beg-syntax () 1639 (cdr (assoc op '((?< . ?>))))))
1826 "Return the syntax cell for a line that may begin a heredoc. 1640 parse-sexp-lookup-properties)
1827See the definition of `ruby-font-lock-syntactic-keywords'. 1641 (save-excursion
1828 1642 (condition-case nil
1829This sets the syntax cell for the newline ending the line 1643 (progn
1830containing the heredoc beginning so that cases where multiple 1644 (if cl ; Paired delimiters.
1831heredocs are started on one line are handled correctly." 1645 ;; Delimiter pairs of the same kind can be nested
1832 (save-excursion 1646 ;; inside the literal, as long as they are balanced.
1833 (goto-char (match-beginning 0)) 1647 ;; Create syntax table that ignores other characters.
1834 (unless (or (ruby-in-ppss-context-p 'non-heredoc) 1648 (with-syntax-table (make-char-table 'syntax-table nil)
1835 (ruby-in-here-doc-p)) 1649 (modify-syntax-entry op (concat "(" (char-to-string cl)))
1836 (string-to-syntax "\"")))) 1650 (modify-syntax-entry cl (concat ")" ops))
1837 1651 (modify-syntax-entry ?\\ "\\")
1838 (defun ruby-here-doc-end-syntax () 1652 (save-restriction
1839 "Return the syntax cell for a line that may end a heredoc. 1653 (narrow-to-region (point) limit)
1840See the definition of `ruby-font-lock-syntactic-keywords'." 1654 (forward-list))) ; skip to the paired character
1841 (let ((pss (syntax-ppss)) (case-fold-search nil)) 1655 ;; Single character delimiter.
1842 ;; If we aren't in a string, we definitely aren't ending a heredoc, 1656 (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
1843 ;; so we can just give up. 1657 (regexp-quote ops)) limit nil))
1844 ;; This means we aren't doing a full-document search 1658 ;; Found the closing delimiter.
1845 ;; every time we enter a character. 1659 (put-text-property (1- (point)) (point) 'syntax-table
1846 (when (ruby-in-ppss-context-p 'heredoc pss) 1660 (string-to-syntax "|")))
1661 ;; Unclosed literal, do nothing.
1662 ((scan-error search-failed)))))))
1663
1664(defun ruby-syntax-propertize-expansion ()
1665 ;; Save the match data to a text property, for font-locking later.
1666 ;; Set the syntax of all double quotes and backticks to punctuation.
1667 (let* ((beg (match-beginning 2))
1668 (end (match-end 2))
1669 (state (and beg (save-excursion (syntax-ppss beg)))))
1670 (when (ruby-syntax-expansion-allowed-p state)
1671 (put-text-property beg (1+ beg) 'ruby-expansion-match-data
1672 (match-data))
1673 (goto-char beg)
1674 (while (re-search-forward "[\"`]" end 'move)
1675 (put-text-property (match-beginning 0) (match-end 0)
1676 'syntax-table (string-to-syntax "."))))))
1677
1678(defun ruby-syntax-expansion-allowed-p (parse-state)
1679 "Return non-nil if expression expansion is allowed."
1680 (let ((term (nth 3 parse-state)))
1681 (cond
1682 ((memq term '(?\" ?` ?\n ?/)))
1683 ((eq term t)
1684 (save-match-data
1847 (save-excursion 1685 (save-excursion
1848 (goto-char (nth 8 pss)) ; Go to the beginning of heredoc. 1686 (goto-char (nth 8 parse-state))
1849 (let ((eol (point))) 1687 (looking-at "%\\(?:[QWrxI]\\|\\W\\)")))))))
1850 (beginning-of-line)
1851 (if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line...
1852 (not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment...
1853 (progn (goto-char (match-end 0)) ; And it's the last heredoc on its line...
1854 (not (re-search-forward ruby-here-doc-beg-re eol t))))
1855 (string-to-syntax "\"")))))))
1856 1688
1857 (unless (functionp 'syntax-ppss) 1689(defun ruby-syntax-propertize-expansions (start end)
1858 (defun syntax-ppss (&optional pos) 1690 (save-excursion
1859 (parse-partial-sexp (point-min) (or pos (point))))) 1691 (goto-char start)
1860 ) 1692 (while (re-search-forward ruby-expression-expansion-re end 'move)
1693 (ruby-syntax-propertize-expansion))))
1861 1694
1862(defun ruby-in-ppss-context-p (context &optional ppss) 1695(defun ruby-in-ppss-context-p (context &optional ppss)
1863 (let ((ppss (or ppss (syntax-ppss (point))))) 1696 (let ((ppss (or ppss (syntax-ppss (point)))))
@@ -1880,14 +1713,6 @@ See the definition of `ruby-font-lock-syntactic-keywords'."
1880 "context name `" (symbol-name context) "' is unknown")))) 1713 "context name `" (symbol-name context) "' is unknown"))))
1881 t))) 1714 t)))
1882 1715
1883(if (featurep 'xemacs)
1884 (put 'ruby-mode 'font-lock-defaults
1885 '((ruby-font-lock-keywords)
1886 nil nil nil
1887 beginning-of-line
1888 (font-lock-syntactic-keywords
1889 . ruby-font-lock-syntactic-keywords))))
1890
1891(defvar ruby-font-lock-syntax-table 1716(defvar ruby-font-lock-syntax-table
1892 (let ((tbl (copy-syntax-table ruby-mode-syntax-table))) 1717 (let ((tbl (copy-syntax-table ruby-mode-syntax-table)))
1893 (modify-syntax-entry ?_ "w" tbl) 1718 (modify-syntax-entry ?_ "w" tbl)
@@ -2082,9 +1907,7 @@ The variable `ruby-indent-level' controls the amount of indentation.
2082 (setq-local font-lock-keywords ruby-font-lock-keywords) 1907 (setq-local font-lock-keywords ruby-font-lock-keywords)
2083 (setq-local font-lock-syntax-table ruby-font-lock-syntax-table) 1908 (setq-local font-lock-syntax-table ruby-font-lock-syntax-table)
2084 1909
2085 (if (eval-when-compile (fboundp 'syntax-propertize-rules)) 1910 (setq-local syntax-propertize-function #'ruby-syntax-propertize-function))
2086 (setq-local syntax-propertize-function #'ruby-syntax-propertize-function)
2087 (setq-local font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))
2088 1911
2089;;; Invoke ruby-mode when appropriate 1912;;; Invoke ruby-mode when appropriate
2090 1913