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.
This commit is contained in:
parent
3a6df2d604
commit
6463b85aeb
3 changed files with 125 additions and 34 deletions
|
@ -1708,46 +1708,127 @@ comment at the start of cc-engine.el for more info."
|
|||
`((c-debug-remove-face beg end 'c-debug-is-sws-face)
|
||||
(c-debug-remove-face beg end 'c-debug-in-sws-face)))))
|
||||
|
||||
(defsubst c-invalidate-sws-region-after (beg end)
|
||||
;; Called from `after-change-functions'. Note that if
|
||||
;; `c-forward-sws' or `c-backward-sws' are used outside
|
||||
;; The type of literal position `end' is in in a `before-change-functions'
|
||||
;; function - one of `c', `c++', `pound', or nil (but NOT `string').
|
||||
(defvar c-sws-lit-type nil)
|
||||
;; A cons (START . STOP) of the bounds of the comment or CPP construct
|
||||
;; enclosing END, if any, else nil.
|
||||
(defvar c-sws-lit-limits nil)
|
||||
|
||||
(defun c-invalidate-sws-region-before (end)
|
||||
;; Called from c-before-change. END is the end of the change region, the
|
||||
;; standard parameter given to all before-change-functions.
|
||||
;;
|
||||
;; Note whether END is inside a comment or CPP construct, and if so note its
|
||||
;; bounds in `c-sws-lit-limits' and type in `c-sws-lit-type'.
|
||||
(save-excursion
|
||||
(goto-char end)
|
||||
(let* ((limits (c-literal-limits))
|
||||
(lit-type (c-literal-type limits)))
|
||||
(cond
|
||||
((memq lit-type '(c c++))
|
||||
(setq c-sws-lit-type lit-type
|
||||
c-sws-lit-limits limits))
|
||||
((c-beginning-of-macro)
|
||||
(setq c-sws-lit-type 'pound
|
||||
c-sws-lit-limits (cons (point)
|
||||
(progn (c-end-of-macro) (point)))))
|
||||
(t (setq c-sws-lit-type nil
|
||||
c-sws-lit-limits nil))))))
|
||||
|
||||
(defun c-invalidate-sws-region-after-del (beg end old-len)
|
||||
;; Text has been deleted, OLD-LEN characters of it starting from position
|
||||
;; BEG. END is typically eq to BEG. Should there have been a comment or
|
||||
;; CPP construct open at END before the deletion, check whether this
|
||||
;; deletion deleted or "damaged" its opening delimiter. If so, return the
|
||||
;; current position of where the construct ended, otherwise return nil.
|
||||
(when c-sws-lit-limits
|
||||
(setcdr c-sws-lit-limits (- (cdr c-sws-lit-limits) old-len))
|
||||
(if (and (< beg (+ (car c-sws-lit-limits) 2)) ; A lazy assumption that
|
||||
; comment delimiters are 2
|
||||
; chars long.
|
||||
(or (get-text-property end 'c-in-sws)
|
||||
(next-single-property-change end 'c-in-sws nil
|
||||
(cdr c-sws-lit-limits))
|
||||
(get-text-property end 'c-is-sws)
|
||||
(next-single-property-change end 'c-is-sws nil
|
||||
(cdr c-sws-lit-limits))))
|
||||
(cdr c-sws-lit-limits))))
|
||||
|
||||
(defun c-invalidate-sws-region-after-ins (end)
|
||||
;; Text has been inserted, ending at buffer position END. Should there be a
|
||||
;; literal or CPP construct open at END, check whether there are `c-in-sws'
|
||||
;; or `c-is-sws' text properties inside this literal. If there are, return
|
||||
;; the buffer position of the end of the literal, else return nil.
|
||||
(save-excursion
|
||||
(let* ((limits (c-literal-limits))
|
||||
(lit-type (c-literal-type limits)))
|
||||
(goto-char end)
|
||||
(when (and (not (memq lit-type '(c c++)))
|
||||
(c-beginning-of-macro))
|
||||
(setq lit-type 'pound
|
||||
limits (cons (point)
|
||||
(progn (c-end-of-macro) (point)))))
|
||||
(when (memq lit-type '(c c++ pound))
|
||||
(let ((next-in (next-single-property-change (car limits) 'c-in-sws
|
||||
nil (cdr limits)))
|
||||
(next-is (next-single-property-change (car limits) 'c-is-sws
|
||||
nil (cdr limits))))
|
||||
(and (or next-in next-is)
|
||||
(cdr limits)))))))
|
||||
|
||||
(defun c-invalidate-sws-region-after (beg end old-len)
|
||||
;; Called from `after-change-functions'. Remove any stale `c-in-sws' or
|
||||
;; `c-is-sws' text properties from the vicinity of the change. BEG, END,
|
||||
;; and OLD-LEN are the standard arguments given to after-change functions.
|
||||
;;
|
||||
;; Note that if `c-forward-sws' or `c-backward-sws' are used outside
|
||||
;; `c-save-buffer-state' or similar then this will remove the cache
|
||||
;; properties right after they're added.
|
||||
;;
|
||||
;; This function does hidden buffer changes.
|
||||
(let ((del-end
|
||||
(and (> old-len 0)
|
||||
(c-invalidate-sws-region-after-del beg end old-len)))
|
||||
(ins-end
|
||||
(and (> end beg)
|
||||
(c-invalidate-sws-region-after-ins end))))
|
||||
(save-excursion
|
||||
;; Adjust the end to remove the properties in any following simple
|
||||
;; ws up to and including the next line break, if there is any
|
||||
;; after the changed region. This is necessary e.g. when a rung
|
||||
;; marked empty line is converted to a line comment by inserting
|
||||
;; "//" before the line break. In that case the line break would
|
||||
;; keep the rung mark which could make a later `c-backward-sws'
|
||||
;; move into the line comment instead of over it.
|
||||
(goto-char end)
|
||||
(skip-chars-forward " \t\f\v")
|
||||
(when (and (eolp) (not (eobp)))
|
||||
(setq end (1+ (point)))))
|
||||
|
||||
(save-excursion
|
||||
;; Adjust the end to remove the properties in any following simple
|
||||
;; ws up to and including the next line break, if there is any
|
||||
;; after the changed region. This is necessary e.g. when a rung
|
||||
;; marked empty line is converted to a line comment by inserting
|
||||
;; "//" before the line break. In that case the line break would
|
||||
;; keep the rung mark which could make a later `c-backward-sws'
|
||||
;; move into the line comment instead of over it.
|
||||
(goto-char end)
|
||||
(skip-chars-forward " \t\f\v")
|
||||
(when (and (eolp) (not (eobp)))
|
||||
(setq end (1+ (point)))))
|
||||
(when (and (= beg end)
|
||||
(get-text-property beg 'c-in-sws)
|
||||
(> beg (point-min))
|
||||
(get-text-property (1- beg) 'c-in-sws))
|
||||
;; Ensure that an `c-in-sws' range gets broken. Note that it isn't
|
||||
;; safe to keep a range that was continuous before the change. E.g:
|
||||
;;
|
||||
;; #define foo
|
||||
;; \
|
||||
;; bar
|
||||
;;
|
||||
;; There can be a "ladder" between "#" and "b". Now, if the newline
|
||||
;; after "foo" is removed then "bar" will become part of the cpp
|
||||
;; directive instead of a syntactically relevant token. In that
|
||||
;; case there's no longer syntactic ws from "#" to "b".
|
||||
(setq beg (1- beg)))
|
||||
|
||||
(when (and (= beg end)
|
||||
(get-text-property beg 'c-in-sws)
|
||||
(> beg (point-min))
|
||||
(get-text-property (1- beg) 'c-in-sws))
|
||||
;; Ensure that an `c-in-sws' range gets broken. Note that it isn't
|
||||
;; safe to keep a range that was continuous before the change. E.g:
|
||||
;;
|
||||
;; #define foo
|
||||
;; \
|
||||
;; bar
|
||||
;;
|
||||
;; There can be a "ladder" between "#" and "b". Now, if the newline
|
||||
;; after "foo" is removed then "bar" will become part of the cpp
|
||||
;; directive instead of a syntactically relevant token. In that
|
||||
;; case there's no longer syntactic ws from "#" to "b".
|
||||
(setq beg (1- beg)))
|
||||
(setq end (max (or del-end end)
|
||||
(or ins-end end)
|
||||
end))
|
||||
|
||||
(c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end)
|
||||
(c-remove-is-and-in-sws beg end))
|
||||
(c-debug-sws-msg "c-invalidate-sws-region-after [%s..%s]" beg end)
|
||||
(c-remove-is-and-in-sws beg end)))
|
||||
|
||||
(defun c-forward-sws ()
|
||||
;; Used by `c-forward-syntactic-ws' to implement the unbounded search.
|
||||
|
|
|
@ -1445,6 +1445,15 @@ properly."
|
|||
t "*/"
|
||||
awk nil)
|
||||
|
||||
(c-lang-defconst c-block-comment-ender-regexp
|
||||
;; Regexp which matches the end of a block comment (if such exists in the
|
||||
;; language)
|
||||
t (if (c-lang-const c-block-comment-ender)
|
||||
(regexp-quote (c-lang-const c-block-comment-ender))
|
||||
"\\<\\>"))
|
||||
(c-lang-defvar c-block-comment-ender-regexp
|
||||
(c-lang-const c-block-comment-ender-regexp))
|
||||
|
||||
(c-lang-defconst c-comment-start-regexp
|
||||
;; Regexp to match the start of any type of comment.
|
||||
t (let ((re (c-make-keywords-re nil
|
||||
|
|
|
@ -1209,6 +1209,7 @@ Note that the style variables are always made local to the buffer."
|
|||
;; Are we coalescing two tokens together, e.g. "fo o" -> "foo"?
|
||||
(when (< beg end)
|
||||
(c-unfind-coalesced-tokens beg end))
|
||||
(c-invalidate-sws-region-before end)
|
||||
;; Are we (potentially) disrupting the syntactic context which
|
||||
;; makes a type a type? E.g. by inserting stuff after "foo" in
|
||||
;; "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."
|
|||
(c-clear-char-property-with-value beg end 'syntax-table nil)))
|
||||
|
||||
(c-trim-found-types beg end old-len) ; maybe we don't need all of these.
|
||||
(c-invalidate-sws-region-after beg end)
|
||||
(c-invalidate-sws-region-after beg end old-len)
|
||||
;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
|
||||
(c-invalidate-find-decl-cache beg)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue