(progn (goto-char beg)
(c-skip-ws-forward end+1)
(eq (point) end+1))))))
+
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We maintain a sopisticated cache of positions which are in a literal,
;; POS (default point) is at a < character. If it is both marked
;; with open/close paren syntax-table property, and has a matching >
;; (also marked) which is after LIM, remove the property both from
- ;; the current > and its partner. Return t when this happens, nil
- ;; when it doesn't.
+ ;; the current > and its partner. Return the position after the >
+ ;; when this happens, nil when it doesn't.
(save-excursion
(if pos
(goto-char pos)
c->-as-paren-syntax)) ; should always be true.
(c-unmark-<->-as-paren (1- (point)))
(c-unmark-<->-as-paren pos)
- (c-truncate-lit-pos-cache pos))
- t)))
+ (c-truncate-lit-pos-cache pos)
+ (point)))))
(defun c-clear->-pair-props-if-match-before (lim &optional pos)
;; POS (default point) is at a > character. If it is both marked
;; with open/close paren syntax-table property, and has a matching <
;; (also marked) which is before LIM, remove the property both from
- ;; the current < and its partner. Return t when this happens, nil
- ;; when it doesn't.
+ ;; the current < and its partner. Return the position of the < when
+ ;; this happens, nil when it doesn't.
(save-excursion
(if pos
(goto-char pos)
c-<-as-paren-syntax)) ; should always be true.
(c-unmark-<->-as-paren (point))
(c-truncate-lit-pos-cache (point))
- (c-unmark-<->-as-paren pos))
- t)))
+ (c-unmark-<->-as-paren pos)
+ (point)))))
;; Set by c-common-init in cc-mode.el.
(defvar c-new-BEG)
;; Set by c-before-change-check-raw-strings.
(defvar c-old-END-literality)
-(defun c-before-change-check-<>-operators (beg end)
+(defun c-end-of-literal (pt-s pt-search)
+ ;; If a literal is open in the `c-semi-pp-to-literal' state PT-S, return the
+ ;; end point of this literal (or point-max) assuming PT-S is valid at
+ ;; PT-SEARCH. Otherwise, return nil.
+ (when (car (cddr pt-s)) ; Literal start
+ (let ((lit-type (cadr pt-s))
+ (lit-beg (car (cddr pt-s)))
+ ml-end-re
+ )
+ (save-excursion
+ (cond
+ ((eq lit-type 'string)
+ (if (and c-ml-string-opener-re
+ (c-ml-string-opener-at-or-around-point lit-beg))
+ (progn
+ (setq ml-end-re
+ (funcall c-make-ml-string-closer-re-function
+ (match-string 1)))
+ (goto-char (max (- pt-search (1- (length ml-end-re)))
+ (point-min)))
+ (re-search-forward ml-end-re nil 'stay))
+ ;; For an ordinary string, we can't use `parse-partial-sexp' since
+ ;; not all syntax-table properties have yet been set.
+ (goto-char pt-search)
+ (re-search-forward
+ "\\(?:\\\\\\(?:.\\|\n\\)\\|[^\"\n\\]\\)*[\"\n]" nil 'stay)))
+ ((memq lit-type '(c c++))
+ ;; To work around a bug in parse-partial-sexp, where effect is given
+ ;; to the syntax of a backslash, even the the scan starts with point
+ ;; just after it.
+ (if (and (eq (char-before pt-search) ?\\)
+ (eq (char-after pt-search) ?\n))
+ (progn
+ (c-put-char-property (1- pt-search) 'syntax-table '(1))
+ (parse-partial-sexp pt-search (point-max) nil nil (car pt-s)
+ 'syntax-table)
+ (c-clear-char-property (1- pt-search) 'syntax-table))
+ (parse-partial-sexp pt-search (point-max) nil nil (car pt-s)
+ 'syntax-table))))
+ (point)))))
+
+(defun c-unmark-<>-around-region (beg end &optional old-len)
;; Unmark certain pairs of "< .... >" which are currently marked as
;; template/generic delimiters. (This marking is via syntax-table text
;; properties), and expand the (c-new-BEG c-new-END) region to include all
;; enclose a brace or semicolon, so we use these as bounds on the
;; region we must work on.
;;
+ ;; The buffer is widened, and point is undefined, both at entry and exit.
+ ;;
+ ;; FIXME!!! This routine ignores the possibility of macros entirely.
+ ;; 2010-01-29.
+
+ (when (> end beg)
+ ;; Extend the region (BEG END) to deal with any complicating literals.
+ (let* ((lit-search-beg (if (memq (char-before beg) '(?/ ?*))
+ (1- beg) beg))
+ (lit-search-end (if (memq (char-after end) '(?/ ?*))
+ (1+ end) end))
+ ;; Note we can't use c-full-pp-to-literal here, since we haven't
+ ;; yet applied syntax-table properties to ends of lines, etc.
+ (lit-search-beg-s (c-semi-pp-to-literal lit-search-beg))
+ (beg-literal-beg (car (cddr lit-search-beg-s)))
+ (lit-search-end-s (c-semi-pp-to-literal lit-search-end))
+ (end-literal-beg (car (cddr lit-search-end-s)))
+ (beg-literal-end (c-end-of-literal lit-search-beg-s beg))
+ (end-literal-end (c-end-of-literal lit-search-end-s end))
+ new-beg new-end search-region)
+
+ ;; Determine any new end of literal resulting from the insertion/deletion.
+ (setq search-region
+ (if (and (eq beg-literal-beg end-literal-beg)
+ (eq beg-literal-end end-literal-end))
+ (if beg-literal-beg
+ nil
+ (cons beg
+ (max end
+ (or beg-literal-end (point-min))
+ (or end-literal-end (point-min)))))
+ (cons (or beg-literal-beg beg)
+ (max end
+ (or beg-literal-end (point-min))
+ (or end-literal-end (point-min))))))
+
+ (when search-region
+ ;; If we've just inserted text, mask its syntaxes temporarily so that
+ ;; they won't interfere with the undoing of the properties on the <s
+ ;; and >s.
+ (c-save-buffer-state (syn-tab-settings syn-tab-value
+ swap-open-string-ends)
+ (unwind-protect
+ (progn
+ (when old-len
+ ;; Special case: If a \ has just been inserted into a
+ ;; string, escaping or unescaping a LF, temporarily swap
+ ;; the LF's syntax-table text property with that of the
+ ;; former end of the open string.
+ (goto-char end)
+ (when (and (eq (cadr lit-search-beg-s) 'string)
+ (not (eq beg-literal-end end-literal-end))
+ (skip-chars-forward "\\\\")
+ (eq (char-after) ?\n)
+ (not (zerop (skip-chars-backward "\\\\"))))
+ (setq swap-open-string-ends t)
+ (if (c-get-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (progn
+ (c-clear-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (c-put-char-property (1- end-literal-end)
+ 'syntax-table '(15)))
+ (c-put-char-property (1- beg-literal-end)
+ 'syntax-table '(15))
+ (c-clear-char-property (1- end-literal-end)
+ 'syntax-table)))
+
+ ;; Save current settings of the 'syntax-table property in
+ ;; (BEG END), then splat these with the punctuation value.
+ (goto-char beg)
+ (while (progn (skip-syntax-forward "" end)
+ (< (point) end))
+ (setq syn-tab-value
+ (c-get-char-property (point) 'syntax-table))
+ (when (not (c-get-char-property (point) 'category))
+ (push (cons (point) syn-tab-value) syn-tab-settings))
+ (forward-char))
+
+ (c-put-char-properties beg end 'syntax-table '(1))
+ ;; If an open string's opener has just been neutralized,
+ ;; do the same to the terminating LF.
+ (when (and end-literal-end
+ (eq (char-before end-literal-end) ?\n)
+ (equal (c-get-char-property
+ (1- end-literal-end) 'syntax-table)
+ '(15)))
+ (push (cons (1- end-literal-end) '(15)) syn-tab-settings)
+ (c-put-char-property (1- end-literal-end) 'syntax-table
+ '(1))))
+
+ (let
+ ((beg-lit-start (progn (goto-char beg) (c-literal-start)))
+ beg-limit end-limit <>-pos)
+ ;; Locate the earliest < after the barrier before the
+ ;; changed region, which isn't already marked as a paren.
+ (goto-char (or beg-lit-start beg))
+ (setq beg-limit (c-determine-limit 5000))
+
+ ;; Remove the syntax-table/category properties from each pertinent <...>
+ ;; pair. Firstly, the ones with the < before beg and > after beg....
+ (goto-char (cdr search-region))
+ (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
+ (eq (char-before) ?<))
+ (c-backward-token-2)
+ (when (eq (char-after) ?<)
+ (when (setq <>-pos (c-clear-<-pair-props-if-match-after
+ (car search-region)))
+ (setq new-end <>-pos))
+ (setq new-beg (point))))
+
+ ;; ...Then the ones with < before end and > after end.
+ (goto-char (car search-region))
+ (setq end-limit (c-determine-+ve-limit 5000))
+ (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
+ (eq (char-before) ?>))
+ (when (eq (char-before) ?>)
+ (if (and (looking-at c->-op-cont-regexp)
+ (not (eq (char-after) ?>)))
+ (goto-char (match-end 0))
+ (when
+ (and (setq <>-pos
+ (c-clear->-pair-props-if-match-before
+ (cdr search-region)
+ (1- (point))))
+ (or (not new-beg)
+ (< <>-pos new-beg)))
+ (setq new-beg <>-pos))
+ (when (or (not new-end) (> (point) new-end))
+ (setq new-end (point))))))))
+
+ (when old-len
+ (c-clear-char-properties beg end 'syntax-table)
+ (dolist (elt syn-tab-settings)
+ (if (cdr elt)
+ (c-put-char-property (car elt) 'syntax-table (cdr elt)))))
+ ;; Swap the '(15) syntax-table property on open string LFs back
+ ;; again.
+ (when swap-open-string-ends
+ (if (c-get-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (progn
+ (c-clear-char-property (1- beg-literal-end)
+ 'syntax-table)
+ (c-put-char-property (1- end-literal-end)
+ 'syntax-table '(15)))
+ (c-put-char-property (1- beg-literal-end)
+ 'syntax-table '(15))
+ (c-clear-char-property (1- end-literal-end)
+ 'syntax-table)))))
+ ;; Extend the fontification region, if needed.
+ (and new-beg
+ (< new-beg c-new-BEG)
+ (setq c-new-BEG new-beg))
+ (and new-end
+ (> new-end c-new-END)
+ (setq c-new-END new-end))))))
+
+(defun c-before-change-check-<>-operators (beg end)
+ ;; When we're deleting text, unmark certain pairs of "< .... >" which are
+ ;; currently marked as template/generic delimiters. (This marking is via
+ ;; syntax-table text properties), and expand the (c-new-BEG c-new-END)
+ ;; region to include all unmarked < and > operators within the certain
+ ;; bounds (see below).
+ ;;
+ ;; These pairs are those which are in the current "statement" (i.e.,
+ ;; the region between the {, }, or ; before BEG and the one after
+ ;; END), and which enclose any part of the interval (BEG END).
+ ;; Also unmark a < or > which is about to become part of a multi-character
+ ;; operator, e.g. <=.
+ ;;
+ ;; Note that in C++ (?and Java), template/generic parens cannot
+ ;; enclose a brace or semicolon, so we use these as bounds on the
+ ;; region we must work on.
+ ;;
;; This function is called from before-change-functions (via
;; c-get-state-before-change-functions). Thus the buffer is widened,
;; and point is undefined, both at entry and exit.
;;
;; FIXME!!! This routine ignores the possibility of macros entirely.
;; 2010-01-29.
- (when (and (or (> end beg)
- (and (> c-<-pseudo-digraph-cont-len 0)
- (goto-char beg)
- (progn
- (skip-chars-backward
- "^<" (max (- (point) c-<-pseudo-digraph-cont-len)
- (point-min)))
- (eq (char-before) ?<))
- (looking-at c-<-pseudo-digraph-cont-regexp)))
- (or
- (progn
- (goto-char beg)
- (search-backward "<" (max (- (point) 1024) (point-min)) t))
- (progn
- (goto-char end)
- (search-forward ">" (min (+ (point) 1024) (point-max)) t))))
- (save-excursion
- (c-save-buffer-state
- ((beg-lit-start (progn (goto-char beg) (c-literal-start)))
- (end-lit-limits (progn (goto-char end) (c-literal-limits)))
- new-beg new-end beg-limit end-limit)
- ;; Locate the earliest < after the barrier before the changed region,
- ;; which isn't already marked as a paren.
- (goto-char (or beg-lit-start beg))
- (setq beg-limit (c-determine-limit 512))
-
- ;; Remove the syntax-table/category properties from each pertinent <...>
- ;; pair. Firstly, the ones with the < before beg and > after beg....
- (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit)
- (eq (char-before) ?<))
- (c-backward-token-2)
- (when (eq (char-after) ?<)
- (c-clear-<-pair-props-if-match-after beg)
- (setq new-beg (point))))
- (c-forward-syntactic-ws)
-
- ;; ...Then the ones with < before end and > after end.
- (goto-char (if end-lit-limits (cdr end-lit-limits) end))
- (setq end-limit (c-determine-+ve-limit 512))
- (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end)
- (eq (char-before) ?>))
- (c-end-of-current-token)
- (when (eq (char-before) ?>)
- (c-clear->-pair-props-if-match-before end (1- (point)))
- (setq new-end (point))))
- (c-backward-syntactic-ws)
-
- ;; Extend the fontification region, if needed.
- (and new-beg
- (< new-beg c-new-BEG)
- (setq c-new-BEG new-beg))
- (and new-end
- (> new-end c-new-END)
- (setq c-new-END new-end))))))
+ (when (> end beg)
+ ;; Cope with removing (beg end) coalescing a < or > with, say, an = sign.
+ (goto-char beg)
+ (let ((ch (char-before)))
+ (if (and (memq ch '(?< ?>))
+ (c-get-char-property (1- (point)) 'syntax-table)
+ (progn
+ (goto-char end)
+ (looking-at (if (eq ch ?<)
+ c-<-op-cont-regexp
+ c->-op-cont-regexp)))
+ (or (eq ch ?<)
+ (not (eq (char-after) ?>))))
+ (c-unmark-<>-around-region (1- beg) beg)))))
(defun c-after-change-check-<>-operators (beg end)
;; This is called from `after-change-functions' when
(c-clear-<>-pair-props)
(forward-char)))))))
+(defun c-<>-get-restricted ()
+ ;; With point at the < at the start of the purported <>-arglist, determine
+ ;; the value of `c-restricted-<>-arglists' to use for the call of
+ ;; `c-forward-<>-arglist' starting there.
+ (save-excursion
+ (c-backward-token-2)
+ (and (not (looking-at c-opt-<>-sexp-key))
+ (progn (c-backward-syntactic-ws) ; to ( or ,
+ (and (memq (char-before) '(?\( ?,)) ; what about <?
+ (not (eq (c-get-char-property (point) 'c-type)
+ 'c-decl-arg-start)))))))
+
(defun c-restore-<>-properties (_beg _end _old-len)
;; This function is called as an after-change function. It restores the
;; category/syntax-table properties on template/generic <..> pairs between
;; c-new-BEG and c-new-END. It may do hidden buffer changes.
- (c-save-buffer-state ((c-parse-and-markup-<>-arglists t)
- c-restricted-<>-arglists lit-limits)
+ (c-save-buffer-state ((c-parse-and-markup-<>-arglists t) lit-limits)
(goto-char c-new-BEG)
(if (setq lit-limits (c-literal-limits))
(goto-char (cdr lit-limits)))
(while (and (< (point) c-new-END)
- (c-syntactic-re-search-forward "<" c-new-END 'bound))
- (backward-char)
- (save-excursion
- (c-backward-token-2)
- (setq c-restricted-<>-arglists
- (and (not (looking-at c-opt-<>-sexp-key))
- (progn (c-backward-syntactic-ws) ; to ( or ,
- (and (memq (char-before) '(?\( ?,)) ; what about <?
- (not (eq (c-get-char-property (point) 'c-type)
- 'c-decl-arg-start)))))))
- (or (c-forward-<>-arglist nil)
- (c-forward-over-token-and-ws)
- (goto-char c-new-END)))))
+ (c-syntactic-re-search-forward "[<>]" c-new-END 'bound))
+ (if (eq (char-before) ?<)
+ (progn
+ (backward-char)
+ (let ((c-restricted-<>-arglists (c-<>-get-restricted)))
+ (or (c-forward-<>-arglist nil)
+ (c-forward-over-token-and-ws)
+ (goto-char c-new-END))))
+ (save-excursion
+ (when (c-backward-<>-arglist nil nil #'c-<>-get-restricted)
+ (setq c-new-BEG (min c-new-BEG (point)))))))))
\f
;; Handling of CC Mode multi-line strings.
(defun c-ml-string-opener-intersects-region (&optional start finish)
;; If any part of the region [START FINISH] is inside an ml-string opener,
- ;; return a dotted list of the start, end and double-quote position of that
- ;; opener. That list will not include any "context characters" before or
- ;; after the opener. If an opener is found, the match-data will indicate
- ;; it, with (match-string 1) being the entire delimiter, and (match-string
- ;; 2) the "main" double-quote. Otherwise, the match-data is undefined.
- ;; Both START and FINISH default to point. FINISH may not be at an earlier
- ;; buffer position than START.
+ ;; return a dotted list of the start, end and double-quote position of the
+ ;; first such opener. That list wlll not include any "context characters"
+ ;; before or after the opener. If an opener is found, the match-data will
+ ;; indicate it, with (match-string 1) being the entire delimiter, and
+ ;; (match-string 2) the "main" double-quote. Otherwise, the match-data is
+ ;; undefined. Both START and FINISH default to point. FINISH may not be at
+ ;; an earlier buffer position than START.
(let ((here (point)) found)
(or finish (setq finish (point)))
(or start (setq start (point)))
;; If POSITION (default point) is at or inside an ml string opener, return a
;; dotted list of the start and end of that opener, and the position of the
;; double-quote in it. That list will not include any "context characters"
- ;; before or after the opener.
+ ;; before or after the opener. If an opener is found, the match-data will
+ ;; indicate it, with (match-string 1) being the entire delimiter, and
+ ;; (match-string 2) the "main" double-quote. Otherwise, the match-data is
+ ;; undefined.
(let ((here (point))
found)
(or position (setq position (point)))
c-ml-string-opener-re
(min (+ position c-ml-string-max-opener-len) (point-max))
'bound))
- (<= (match-end 1) position)))
+ (< (match-end 1) position)))
(prog1
(and found
(<= (match-beginning 1) position)
(if res
(or c-record-found-types t)))))
-(defun c-backward-<>-arglist (all-types &optional limit)
+(defun c-backward-<>-arglist (all-types &optional limit restricted-function)
;; The point is assumed to be directly after a ">". Try to treat it
;; as the close paren of an angle bracket arglist and move back to
;; the corresponding "<". If successful, the point is left at
;; `c-forward-<>-arglist'.
;;
;; If the optional LIMIT is given, it bounds the backward search.
- ;; It's then assumed to be at a syntactically relevant position.
+ ;; It's then assumed to be at a syntactically relevant position. If
+ ;; RESTRICTED-FUNCTION is non-nil, it should be a function taking no
+ ;; arguments, called with point at a < at the start of a purported
+ ;; <>-arglist, which will return the value of
+ ;; `c-restricted-<>-arglists' to be used in the `c-forward-<>-arglist'
+ ;; call starting at that <.
;;
;; This is a wrapper around `c-forward-<>-arglist'. See that
;; function for more details.
t
(backward-char)
- (let ((beg-pos (point)))
+ (let ((beg-pos (point))
+ (c-restricted-<>-arglists
+ (if restricted-function
+ (funcall restricted-function)
+ c-restricted-<>-arglists)))
(if (c-forward-<>-arglist all-types)
(cond ((= (point) start)
;; Matched the arglist. Break the while.