aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorAlan Mackenzie2017-01-11 18:25:39 +0000
committerAlan Mackenzie2017-01-11 18:25:39 +0000
commit6463b85aeb67326acda340fbaad3e481e62120c0 (patch)
tree888ef48e1defcf0c83acc651fc6db95bb3ea22f8 /lisp
parent3a6df2d6043d32dd9a1864c87de8d99e9739a7e4 (diff)
downloademacs-6463b85aeb67326acda340fbaad3e481e62120c0.tar.gz
emacs-6463b85aeb67326acda340fbaad3e481e62120c0.zip
Handle syntactic WS cache properties more accurately at buffer changes.
This fixes bug #25362. * lisp/progmodes/cc-engine.el (c-sws-lit-type, c-sws-lit-limits) (c-invalidate-sws-region-before, c-invalidate-sws-region-after-del) (c-invalidate-sws-region-after-ins): New variables and functions. (c-invalidate-sws-region-after): Change from a defsubst to a defun. Also pass it the standard OLD-LEN argument. Call both c-invalidate-sws-region-after-{ins,del} to check for "dangerous" WS cache properties. * lisp/progmodes/cc-langs.el (c-block-comment-ender-regexp): New language variable. * lisp/progmodes/cc-mode.el (c-before-change): Call c-invalidate-sws-region-before. (c-after-change): Pass old-len to c-invalidate-sws-region-after.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/progmodes/cc-engine.el153
-rw-r--r--lisp/progmodes/cc-langs.el9
-rw-r--r--lisp/progmodes/cc-mode.el3
3 files changed, 128 insertions, 37 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index a5d25880744..3077e0085d3 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -1708,46 +1708,127 @@ comment at the start of cc-engine.el for more info."
1708 `((c-debug-remove-face beg end 'c-debug-is-sws-face) 1708 `((c-debug-remove-face beg end 'c-debug-is-sws-face)
1709 (c-debug-remove-face beg end 'c-debug-in-sws-face))))) 1709 (c-debug-remove-face beg end 'c-debug-in-sws-face)))))
1710 1710
1711(defsubst c-invalidate-sws-region-after (beg end) 1711;; The type of literal position `end' is in in a `before-change-functions'
1712 ;; Called from `after-change-functions'. Note that if 1712;; function - one of `c', `c++', `pound', or nil (but NOT `string').
1713 ;; `c-forward-sws' or `c-backward-sws' are used outside 1713(defvar c-sws-lit-type nil)
1714;; A cons (START . STOP) of the bounds of the comment or CPP construct
1715;; enclosing END, if any, else nil.
1716(defvar c-sws-lit-limits nil)
1717
1718(defun c-invalidate-sws-region-before (end)
1719 ;; Called from c-before-change. END is the end of the change region, the
1720 ;; standard parameter given to all before-change-functions.
1721 ;;
1722 ;; Note whether END is inside a comment or CPP construct, and if so note its
1723 ;; bounds in `c-sws-lit-limits' and type in `c-sws-lit-type'.
1724 (save-excursion
1725 (goto-char end)
1726 (let* ((limits (c-literal-limits))
1727 (lit-type (c-literal-type limits)))
1728 (cond
1729 ((memq lit-type '(c c++))
1730 (setq c-sws-lit-type lit-type
1731 c-sws-lit-limits limits))
1732 ((c-beginning-of-macro)
1733 (setq c-sws-lit-type 'pound
1734 c-sws-lit-limits (cons (point)
1735 (progn (c-end-of-macro) (point)))))
1736 (t (setq c-sws-lit-type nil
1737 c-sws-lit-limits nil))))))
1738
1739(defun c-invalidate-sws-region-after-del (beg end old-len)
1740 ;; Text has been deleted, OLD-LEN characters of it starting from position
1741 ;; BEG. END is typically eq to BEG. Should there have been a comment or
1742 ;; CPP construct open at END before the deletion, check whether this
1743 ;; deletion deleted or "damaged" its opening delimiter. If so, return the
1744 ;; current position of where the construct ended, otherwise return nil.
1745 (when c-sws-lit-limits
1746 (setcdr c-sws-lit-limits (- (cdr c-sws-lit-limits) old-len))
1747 (if (and (< beg (+ (car c-sws-lit-limits) 2)) ; A lazy assumption that
1748 ; comment delimiters are 2
1749 ; chars long.
1750 (or (get-text-property end 'c-in-sws)
1751 (next-single-property-change end 'c-in-sws nil
1752 (cdr c-sws-lit-limits))
1753 (get-text-property end 'c-is-sws)
1754 (next-single-property-change end 'c-is-sws nil
1755 (cdr c-sws-lit-limits))))
1756 (cdr c-sws-lit-limits))))
1757
1758(defun c-invalidate-sws-region-after-ins (end)
1759 ;; Text has been inserted, ending at buffer position END. Should there be a
1760 ;; literal or CPP construct open at END, check whether there are `c-in-sws'
1761 ;; or `c-is-sws' text properties inside this literal. If there are, return
1762 ;; the buffer position of the end of the literal, else return nil.
1763 (save-excursion
1764 (let* ((limits (c-literal-limits))
1765 (lit-type (c-literal-type limits)))
1766 (goto-char end)
1767 (when (and (not (memq lit-type '(c c++)))
1768 (c-beginning-of-macro))
1769 (setq lit-type 'pound
1770 limits (cons (point)
1771 (progn (c-end-of-macro) (point)))))
1772 (when (memq lit-type '(c c++ pound))
1773 (let ((next-in (next-single-property-change (car limits) 'c-in-sws
1774 nil (cdr limits)))
1775 (next-is (next-single-property-change (car limits) 'c-is-sws
1776 nil (cdr limits))))
1777 (and (or next-in next-is)
1778 (cdr limits)))))))
1779
1780(defun c-invalidate-sws-region-after (beg end old-len)
1781 ;; Called from `after-change-functions'. Remove any stale `c-in-sws' or
1782 ;; `c-is-sws' text properties from the vicinity of the change. BEG, END,
1783 ;; and OLD-LEN are the standard arguments given to after-change functions.
1784 ;;
1785 ;; Note that if `c-forward-sws' or `c-backward-sws' are used outside
1714 ;; `c-save-buffer-state' or similar then this will remove the cache 1786 ;; `c-save-buffer-state' or similar then this will remove the cache
1715 ;; properties right after they're added. 1787 ;; properties right after they're added.
1716 ;; 1788 ;;
1717 ;; This function does hidden buffer changes. 1789 ;; This function does hidden buffer changes.
1718 1790 (let ((del-end
1719 (save-excursion 1791 (and (> old-len 0)
1720 ;; Adjust the end to remove the properties in any following simple 1792 (c-invalidate-sws-region-after-del beg end old-len)))
1721 ;; ws up to and including the next line break, if there is any 1793 (ins-end
1722 ;; after the changed region. This is necessary e.g. when a rung 1794 (and (> end beg)
1723 ;; marked empty line is converted to a line comment by inserting 1795 (c-invalidate-sws-region-after-ins end))))
1724 ;; "//" before the line break. In that case the line break would 1796 (save-excursion
1725 ;; keep the rung mark which could make a later `c-backward-sws' 1797 ;; Adjust the end to remove the properties in any following simple
1726 ;; move into the line comment instead of over it. 1798 ;; ws up to and including the next line break, if there is any
1727 (goto-char end) 1799 ;; after the changed region. This is necessary e.g. when a rung
1728 (skip-chars-forward " \t\f\v") 1800 ;; marked empty line is converted to a line comment by inserting
1729 (when (and (eolp) (not (eobp))) 1801 ;; "//" before the line break. In that case the line break would
1730 (setq end (1+ (point))))) 1802 ;; keep the rung mark which could make a later `c-backward-sws'
1731 1803 ;; move into the line comment instead of over it.
1732 (when (and (= beg end) 1804 (goto-char end)
1733 (get-text-property beg 'c-in-sws) 1805 (skip-chars-forward " \t\f\v")
1734 (> beg (point-min)) 1806 (when (and (eolp) (not (eobp)))
1735 (get-text-property (1- beg) 'c-in-sws)) 1807 (setq end (1+ (point)))))
1736 ;; Ensure that an `c-in-sws' range gets broken. Note that it isn't 1808
1737 ;; safe to keep a range that was continuous before the change. E.g: 1809 (when (and (= beg end)
1738 ;; 1810 (get-text-property beg 'c-in-sws)
1739 ;; #define foo 1811 (> beg (point-min))
1740 ;; \ 1812 (get-text-property (1- beg) 'c-in-sws))
1741 ;; bar 1813 ;; Ensure that an `c-in-sws' range gets broken. Note that it isn't
1742 ;; 1814 ;; safe to keep a range that was continuous before the change. E.g:
1743 ;; There can be a "ladder" between "#" and "b". Now, if the newline 1815 ;;
1744 ;; after "foo" is removed then "bar" will become part of the cpp 1816 ;; #define foo
1745 ;; directive instead of a syntactically relevant token. In that 1817 ;; \
1746 ;; case there's no longer syntactic ws from "#" to "b". 1818 ;; bar
1747 (setq beg (1- beg))) 1819 ;;
1748 1820 ;; There can be a "ladder" between "#" and "b". Now, if the newline
1749 (c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end) 1821 ;; after "foo" is removed then "bar" will become part of the cpp
1750 (c-remove-is-and-in-sws beg end)) 1822 ;; directive instead of a syntactically relevant token. In that
1823 ;; case there's no longer syntactic ws from "#" to "b".
1824 (setq beg (1- beg)))
1825
1826 (setq end (max (or del-end end)
1827 (or ins-end end)
1828 end))
1829
1830 (c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end)
1831 (c-remove-is-and-in-sws beg end)))
1751 1832
1752(defun c-forward-sws () 1833(defun c-forward-sws ()
1753 ;; Used by `c-forward-syntactic-ws' to implement the unbounded search. 1834 ;; Used by `c-forward-syntactic-ws' to implement the unbounded search.
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 87aeaa4750f..037404696d6 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -1445,6 +1445,15 @@ properly."
1445 t "*/" 1445 t "*/"
1446 awk nil) 1446 awk nil)
1447 1447
1448(c-lang-defconst c-block-comment-ender-regexp
1449 ;; Regexp which matches the end of a block comment (if such exists in the
1450 ;; language)
1451 t (if (c-lang-const c-block-comment-ender)
1452 (regexp-quote (c-lang-const c-block-comment-ender))
1453 "\\<\\>"))
1454(c-lang-defvar c-block-comment-ender-regexp
1455 (c-lang-const c-block-comment-ender-regexp))
1456
1448(c-lang-defconst c-comment-start-regexp 1457(c-lang-defconst c-comment-start-regexp
1449 ;; Regexp to match the start of any type of comment. 1458 ;; Regexp to match the start of any type of comment.
1450 t (let ((re (c-make-keywords-re nil 1459 t (let ((re (c-make-keywords-re nil
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index ac4ba05bb56..7e3c6ba15a5 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1209,6 +1209,7 @@ Note that the style variables are always made local to the buffer."
1209 ;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"? 1209 ;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
1210 (when (< beg end) 1210 (when (< beg end)
1211 (c-unfind-coalesced-tokens beg end)) 1211 (c-unfind-coalesced-tokens beg end))
1212 (c-invalidate-sws-region-before end)
1212 ;; Are we (potentially) disrupting the syntactic context which 1213 ;; Are we (potentially) disrupting the syntactic context which
1213 ;; makes a type a type? E.g. by inserting stuff after "foo" in 1214 ;; makes a type a type? E.g. by inserting stuff after "foo" in
1214 ;; "foo bar;", or before "foo" in "typedef foo *bar;"? 1215 ;; "foo bar;", or before "foo" in "typedef foo *bar;"?
@@ -1338,7 +1339,7 @@ Note that the style variables are always made local to the buffer."
1338 (c-clear-char-property-with-value beg end 'syntax-table nil))) 1339 (c-clear-char-property-with-value beg end 'syntax-table nil)))
1339 1340
1340 (c-trim-found-types beg end old-len) ; maybe we don't need all of these. 1341 (c-trim-found-types beg end old-len) ; maybe we don't need all of these.
1341 (c-invalidate-sws-region-after beg end) 1342 (c-invalidate-sws-region-after beg end old-len)
1342 ;; (c-invalidate-state-cache beg) ; moved to `c-before-change'. 1343 ;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
1343 (c-invalidate-find-decl-cache beg) 1344 (c-invalidate-find-decl-cache beg)
1344 1345