changeset 106522:0a0832d4518d

Fix bug#5091: indentation in c++-mode. * cc-mode.el (c-basic-common-init): make text property `category' rear non-sticky. * cc-engine.el (c-ssb-lit-begin): New defsubst, extracted from .... (c-syntactic-skip-backward): Refactor, extracting the above. (c-guess-basic-syntax CASEs 5D.3, 5L): Add extra anchor point; (c-guess-basic-syntax CASE 19): New CASE to handle template construct continued over line boundary. (c-guess-basic-syntax CASE 7): don't trigger on '<'.
author Alan Mackenzie <acm@muc.de>
date Thu, 10 Dec 2009 14:29:11 +0000
parents 3ecd902dead9
children 413286e97178
files lisp/progmodes/cc-engine.el lisp/progmodes/cc-mode.el
diffstat 2 files changed, 169 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/cc-engine.el	Thu Dec 10 14:24:42 2009 +0000
+++ b/lisp/progmodes/cc-engine.el	Thu Dec 10 14:29:11 2009 +0000
@@ -3743,6 +3743,57 @@
 	(goto-char bound))
       nil)))
 
+(defsubst c-ssb-lit-begin ()
+  ;; Return the start of the literal point is in, or nil.
+  ;; We read and write the variables `safe-pos', `safe-pos-list', `state'
+  ;; bound in the caller.
+
+  ;; Use `parse-partial-sexp' from a safe position down to the point to check
+  ;; if it's outside comments and strings.
+  (save-excursion
+    (let ((pos (point)) safe-pos state pps-end-pos)
+      ;; Pick a safe position as close to the point as possible.
+      ;;
+      ;; FIXME: Consult `syntax-ppss' here if our cache doesn't give a good
+      ;; position.
+    
+      (while (and safe-pos-list
+		  (> (car safe-pos-list) (point)))
+	(setq safe-pos-list (cdr safe-pos-list)))
+      (unless (setq safe-pos (car-safe safe-pos-list))
+	(setq safe-pos (max (or (c-safe-position
+				 (point) (or c-state-cache
+					     (c-parse-state)))
+				0)
+			    (point-min))
+	      safe-pos-list (list safe-pos)))
+
+      ;; Cache positions along the way to use if we have to back up more.  We
+      ;; cache every closing paren on the same level.  If the paren cache is
+      ;; relevant in this region then we're typically already on the same
+      ;; level as the target position.  Note that we might cache positions
+      ;; after opening parens in case safe-pos is in a nested list.  That's
+      ;; both uncommon and harmless.
+      (while (progn
+	       (setq state (parse-partial-sexp
+			    safe-pos pos 0))
+	       (< (point) pos))
+	(setq safe-pos (point)
+	      safe-pos-list (cons safe-pos safe-pos-list)))
+
+      ;; If the state contains the start of the containing sexp we cache that
+      ;; position too, so that parse-partial-sexp in the next run has a bigger
+      ;; chance of starting at the same level as the target position and thus
+      ;; will get more good safe positions into the list.
+      (if (elt state 1)
+	  (setq safe-pos (1+ (elt state 1))
+		safe-pos-list (cons safe-pos safe-pos-list)))
+
+      (if (or (elt state 3) (elt state 4))
+	  ;; Inside string or comment.  Continue search at the
+	  ;; beginning of it.
+	  (elt state 8)))))
+
 (defun c-syntactic-skip-backward (skip-chars &optional limit paren-level)
   "Like `skip-chars-backward' but only look at syntactically relevant chars,
 i.e. don't stop at positions inside syntactic whitespace or string
@@ -3761,140 +3812,100 @@
 comment at the start of cc-engine.el for more info."
 
   (let ((start (point))
-	state
+	state-2
 	;; A list of syntactically relevant positions in descending
 	;; order.  It's used to avoid scanning repeatedly over
 	;; potentially large regions with `parse-partial-sexp' to verify
-	;; each position.
+	;; each position.  Used in `c-ssb-lit-begin'
 	safe-pos-list
-	;; The position at the beginning of `safe-pos-list'.
-	safe-pos
 	;; The result from `c-beginning-of-macro' at the start position or the
 	;; start position itself if it isn't within a macro.  Evaluated on
 	;; demand.
 	start-macro-beg
 	;; The earliest position after the current one with the same paren
 	;; level.  Used only when `paren-level' is set.
+	lit-beg
 	(paren-level-pos (point)))
 
-    (while (progn
-	     (while (and
-		     (< (skip-chars-backward skip-chars limit) 0)
-
-		     ;; Use `parse-partial-sexp' from a safe position down to
-		     ;; the point to check if it's outside comments and
-		     ;; strings.
-		     (let ((pos (point)) state-2 pps-end-pos)
-		       ;; Pick a safe position as close to the point as
-		       ;; possible.
-		       ;;
-		       ;; FIXME: Consult `syntax-ppss' here if our
-		       ;; cache doesn't give a good position.
-		       (while (and safe-pos-list
-				   (> (car safe-pos-list) (point)))
-			 (setq safe-pos-list (cdr safe-pos-list)))
-		       (unless (setq safe-pos (car-safe safe-pos-list))
-			 (setq safe-pos (max (or (c-safe-position
-						  (point) (or c-state-cache
-							      (c-parse-state)))
-						 0)
-					     (point-min))
-			       safe-pos-list (list safe-pos)))
-
-		       ;; Cache positions along the way to use if we have to
-		       ;; back up more.  We cache every closing paren on the
-		       ;; same level.  If the paren cache is relevant in this
-		       ;; region then we're typically already on the same
-		       ;; level as the target position.  Note that we might
-		       ;; cache positions after opening parens in case
-		       ;; safe-pos is in a nested list.  That's both uncommon
-		       ;; and harmless.
-		       (while (progn
-				(setq state (parse-partial-sexp
-					     safe-pos pos 0))
-				(< (point) pos))
-			 (setq safe-pos (point)
-			       safe-pos-list (cons safe-pos safe-pos-list)))
-
-		       (cond
-			((or (elt state 3) (elt state 4))
-			 ;; Inside string or comment.  Continue search at the
-			 ;; beginning of it.
-			 (goto-char (elt state 8))
-			 t)
-
-			((and paren-level
-			      (save-excursion
-				(setq state-2 (parse-partial-sexp
-					       pos paren-level-pos -1)
-				      pps-end-pos (point))
-				(/= (car state-2) 0)))
-			 ;; Not at the right level.
-
-			 (if (and (< (car state-2) 0)
-				  ;; We stop above if we go out of a paren.
-				  ;; Now check whether it precedes or is
-				  ;; nested in the starting sexp.
-				  (save-excursion
-				    (setq state-2
-					  (parse-partial-sexp
-					   pps-end-pos paren-level-pos
-					   nil nil state-2))
-				    (< (car state-2) 0)))
-
-			     ;; We've stopped short of the starting position
-			     ;; so the hit was inside a nested list.  Go up
-			     ;; until we are at the right level.
-			     (condition-case nil
+    (while
+	(progn
+	  ;; The next loop "tries" to find the end point each time round,
+	  ;; loops when it hasn't succeeded.
+	  (while
+	      (and
+	       (< (skip-chars-backward skip-chars limit) 0)
+
+	       (let ((pos (point)) state-2 pps-end-pos)
+
+		 (cond
+		  ;; Don't stop inside a literal
+		  ((setq lit-beg (c-ssb-lit-begin))
+		   (goto-char lit-beg)
+		   t)
+
+		  ((and paren-level
+			(save-excursion
+			  (setq state-2 (parse-partial-sexp
+					 pos paren-level-pos -1)
+				pps-end-pos (point))
+			  (/= (car state-2) 0)))
+		   ;; Not at the right level.
+
+		   (if (and (< (car state-2) 0)
+			    ;; We stop above if we go out of a paren.
+			    ;; Now check whether it precedes or is
+			    ;; nested in the starting sexp.
+			    (save-excursion
+			      (setq state-2
+				    (parse-partial-sexp
+				     pps-end-pos paren-level-pos
+				     nil nil state-2))
+			      (< (car state-2) 0)))
+
+		       ;; We've stopped short of the starting position
+		       ;; so the hit was inside a nested list.  Go up
+		       ;; until we are at the right level.
+		       (condition-case nil
+			   (progn
+			     (goto-char (scan-lists pos -1
+						    (- (car state-2))))
+			     (setq paren-level-pos (point))
+			     (if (and limit (>= limit paren-level-pos))
 				 (progn
-				   (goto-char (scan-lists pos -1
-							  (- (car state-2))))
-				   (setq paren-level-pos (point))
-				   (if (and limit (>= limit paren-level-pos))
-				       (progn
-					 (goto-char limit)
-					 nil)
-				     t))
-			       (error
-				(goto-char (or limit (point-min)))
-				nil))
-
-			   ;; The hit was outside the list at the start
-			   ;; position.  Go to the start of the list and exit.
-			   (goto-char (1+ (elt state-2 1)))
-			   nil))
-
-			((c-beginning-of-macro limit)
-			 ;; Inside a macro.
-			 (if (< (point)
-				(or start-macro-beg
-				    (setq start-macro-beg
-					  (save-excursion
-					    (goto-char start)
-					    (c-beginning-of-macro limit)
-					    (point)))))
-			     t
-
-			   ;; It's inside the same macro we started in so it's
-			   ;; a relevant match.
-			   (goto-char pos)
-			   nil)))))
-
-	       ;; If the state contains the start of the containing sexp we
-	       ;; cache that position too, so that parse-partial-sexp in the
-	       ;; next run has a bigger chance of starting at the same level
-	       ;; as the target position and thus will get more good safe
-	       ;; positions into the list.
-	       (if (elt state 1)
-		   (setq safe-pos (1+ (elt state 1))
-			 safe-pos-list (cons safe-pos safe-pos-list))))
-
-	     (> (point)
-		(progn
-		  ;; Skip syntactic ws afterwards so that we don't stop at the
-		  ;; end of a comment if `skip-chars' is something like "^/".
-		  (c-backward-syntactic-ws)
-		  (point)))))
+				   (goto-char limit)
+				   nil)
+			       t))
+			 (error
+			  (goto-char (or limit (point-min)))
+			  nil))
+
+		     ;; The hit was outside the list at the start
+		     ;; position.  Go to the start of the list and exit.
+		     (goto-char (1+ (elt state-2 1)))
+		     nil))
+
+		  ((c-beginning-of-macro limit)
+		   ;; Inside a macro.
+		   (if (< (point)
+			  (or start-macro-beg
+			      (setq start-macro-beg
+				    (save-excursion
+				      (goto-char start)
+				      (c-beginning-of-macro limit)
+				      (point)))))
+		       t
+
+		     ;; It's inside the same macro we started in so it's
+		     ;; a relevant match.
+		     (goto-char pos)
+		     nil))))))
+	     
+	  (> (point)
+	     (progn
+	       ;; Skip syntactic ws afterwards so that we don't stop at the
+	       ;; end of a comment if `skip-chars' is something like "^/".
+	       (c-backward-syntactic-ws)
+	       (point)))))
 
     ;; We might want to extend this with more useful return values in
     ;; the future.
@@ -8426,6 +8437,7 @@
 	   literal char-before-ip before-ws-ip char-after-ip macro-start
 	   in-macro-expr c-syntactic-context placeholder c-in-literal-cache
 	   step-type tmpsymbol keyword injava-inher special-brace-list tmp-pos
+	   containing-<
 	   ;; The following record some positions for the containing
 	   ;; declaration block if we're directly within one:
 	   ;; `containing-decl-open' is the position of the open
@@ -9040,7 +9052,7 @@
 		  (back-to-indentation)))
 	      ;; FIXME: Should use c-add-stmt-syntax, but it's not yet
 	      ;; template aware.
-	      (c-add-syntax 'template-args-cont (point)))
+	      (c-add-syntax 'template-args-cont (point) placeholder))
 
 	     ;; CASE 5D.4: perhaps a multiple inheritance line?
 	     ((and (c-major-mode-is 'c++-mode)
@@ -9252,10 +9264,11 @@
 	   ;; arglist that begins on the previous line.
 	   ((and c-recognize-<>-arglists
 		 (eq (char-before) ?<)
+		 (setq placeholder (1- (point)))
 		 (not (and c-overloadable-operators-regexp
 			   (c-after-special-operator-id lim))))
 	    (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
-	    (c-add-syntax 'template-args-cont (c-point 'boi)))
+	    (c-add-syntax 'template-args-cont (c-point 'boi) placeholder))
 
 	   ;; CASE 5Q: we are at a statement within a macro.
 	   (macro-start
@@ -9277,14 +9290,38 @@
 
 	 ;; (CASE 6 has been removed.)
 
+	 ;; CASE 19: line is an expression, not a statement, and is directly
+	 ;; contained by a template delimiter.  Most likely, we are in a
+	 ;; template arglist within a statement.  This case is based on CASE
+	 ;; 7.  At some point in the future, we may wish to create more
+	 ;; syntactic symbols such as `template-intro',
+	 ;; `template-cont-nonempty', etc., and distinguish between them as we
+	 ;; do for `arglist-intro' etc. (2009-12-07).
+	 ((and c-recognize-<>-arglists
+	       (setq containing-< (c-up-list-backward indent-point containing-sexp))
+	       (eq (char-after containing-<) ?\<))
+	  (setq placeholder (c-point 'boi containing-<))
+	  (goto-char containing-sexp)	; Most nested Lbrace/Lparen (but not
+					; '<') before indent-point.
+	  (if (>= (point) placeholder)
+	      (progn
+		(forward-char)
+		(skip-chars-forward " \t"))
+	    (goto-char placeholder))
+	  (c-add-stmt-syntax 'template-args-cont (list containing-<) t
+			     (c-most-enclosing-brace c-state-cache (point))
+			     paren-state))
+			     
+
 	 ;; CASE 7: line is an expression, not a statement.  Most
 	 ;; likely we are either in a function prototype or a function
-	 ;; call argument list
+	 ;; call argument list, or a template argument list.
 	 ((not (or (and c-special-brace-lists
 			(save-excursion
 			  (goto-char containing-sexp)
 			  (c-looking-at-special-brace-list)))
-		   (eq (char-after containing-sexp) ?{)))
+		   (eq (char-after containing-sexp) ?{)
+		   (eq (char-after containing-sexp) ?<)))
 	  (cond
 
 	   ;; CASE 7A: we are looking at the arglist closing paren.
@@ -9381,7 +9418,7 @@
 		   (c-forward-syntactic-ws)
 		   (point))
 		 (c-point 'bonl)))
-	    (goto-char containing-sexp)
+	    (goto-char containing-sexp)	; paren opening the arglist
 	    (setq placeholder (c-point 'boi))
 	    (if (and (c-safe (backward-up-list 1) t)
 		     (>= (point) placeholder))
--- a/lisp/progmodes/cc-mode.el	Thu Dec 10 14:24:42 2009 +0000
+++ b/lisp/progmodes/cc-mode.el	Thu Dec 10 14:29:11 2009 +0000
@@ -541,19 +541,15 @@
       (make-local-variable 'lookup-syntax-properties)
       (setq lookup-syntax-properties t)))
 
-  ;; Use this in Emacs 21 to avoid meddling with the rear-nonsticky
+  ;; Use this in Emacs 21+ to avoid meddling with the rear-nonsticky
   ;; property on each character.
   (when (boundp 'text-property-default-nonsticky)
     (make-local-variable 'text-property-default-nonsticky)
-    (let ((elem (assq 'syntax-table text-property-default-nonsticky)))
-      (if elem
-	  (setcdr elem t)
-	(setq text-property-default-nonsticky
-	      (cons '(syntax-table . t)
-		    text-property-default-nonsticky))))
-    (setq text-property-default-nonsticky
-	  (cons '(c-type . t)
-		text-property-default-nonsticky)))
+    (mapc (lambda (tprop)
+	    (unless (assq tprop text-property-default-nonsticky)
+	      (setq text-property-default-nonsticky
+		    (cons `(,tprop . t) text-property-default-nonsticky))))
+	  '(syntax-table category c-type)))
 
   ;; In Emacs 21 and later it's possible to turn off the ad-hoc
   ;; heuristic that open parens in column 0 are defun starters.  Since