From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#5091: indentation in c++-mode Date: Thu, 10 Dec 2009 14:37:17 +0000 Message-ID: <20091210143717.GC1504@muc.de> References: <1259678138.22343.7.camel@imagina04.e-onsoftware.com> Reply-To: Alan Mackenzie , 5091@emacsbugs.donarmstrong.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1260458920 15938 80.91.229.12 (10 Dec 2009 15:28:40 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 10 Dec 2009 15:28:40 +0000 (UTC) To: voddou@e-onsoftware.com, 5091@emacsbugs.donarmstrong.com Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Thu Dec 10 16:28:33 2009 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1NIkwS-0000q4-7H for geb-bug-gnu-emacs@m.gmane.org; Thu, 10 Dec 2009 16:28:32 +0100 Original-Received: from localhost ([127.0.0.1]:60498 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NIkwR-0001kE-EI for geb-bug-gnu-emacs@m.gmane.org; Thu, 10 Dec 2009 10:28:31 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NIkIo-0003C5-36 for bug-gnu-emacs@gnu.org; Thu, 10 Dec 2009 09:47:34 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NIkIj-00037t-Ud for bug-gnu-emacs@gnu.org; Thu, 10 Dec 2009 09:47:33 -0500 Original-Received: from [199.232.76.173] (port=45486 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NIkIj-00037i-I7 for bug-gnu-emacs@gnu.org; Thu, 10 Dec 2009 09:47:29 -0500 Original-Received: from rzlab.ucr.edu ([138.23.92.77]:56479) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NIkIj-0004ck-7y for bug-gnu-emacs@gnu.org; Thu, 10 Dec 2009 09:47:29 -0500 Original-Received: from rzlab.ucr.edu (rzlab.ucr.edu [127.0.0.1]) by rzlab.ucr.edu (8.14.3/8.14.3/Debian-5) with ESMTP id nBAElQN5011038; Thu, 10 Dec 2009 06:47:26 -0800 Original-Received: (from debbugs@localhost) by rzlab.ucr.edu (8.14.3/8.14.3/Submit) id nBAEe68B010153; Thu, 10 Dec 2009 06:40:06 -0800 Resent-Date: Thu, 10 Dec 2009 06:40:06 -0800 X-Loop: owner@emacsbugs.donarmstrong.com Resent-From: Alan Mackenzie Resent-To: bug-submit-list@donarmstrong.com Resent-CC: Emacs Bugs , owner@emacsbugs.donarmstrong.com 2Resent-Date: Thu, 10 Dec 2009 14:40:05 +0000 Resent-Message-ID: Resent-Sender: owner@emacsbugs.donarmstrong.com X-Emacs-PR-Message: followup 5091 X-Emacs-PR-Package: emacs,cc-mode X-Emacs-PR-Keywords: Original-Received: via spool by 5091-submit@emacsbugs.donarmstrong.com id=B5091.12604555089527 (code B ref 5091); Thu, 10 Dec 2009 14:40:05 +0000 Original-Received: (at 5091) by emacsbugs.donarmstrong.com; 10 Dec 2009 14:31:48 +0000 X-Spam-Bayes: score:0.5 Bayes not run. spammytokens:Tokens not available. hammytokens:Tokens not available. Original-Received: from mail.muc.de (qmailr@colin.muc.de [193.149.48.1]) by rzlab.ucr.edu (8.14.3/8.14.3/Debian-5) with ESMTP id nBAEVhpI009520 for <5091@emacsbugs.donarmstrong.com>; Thu, 10 Dec 2009 06:31:47 -0800 Original-Received: (qmail 6097 invoked by uid 3782); 10 Dec 2009 14:31:42 -0000 Original-Received: from acm.muc.de (pD9E51273.dip.t-dialin.net [217.229.18.115]) by colin2.muc.de (tmda-ofmipd) with ESMTP; Thu, 10 Dec 2009 15:31:40 +0100 Original-Received: (qmail 15219 invoked by uid 1000); 10 Dec 2009 14:37:17 -0000 Content-Disposition: inline In-Reply-To: <1259678138.22343.7.camel@imagina04.e-onsoftware.com> User-Agent: Mutt/1.5.9i X-Delivery-Agent: TMDA/1.1.5 (Fettercairn) X-Primary-Address: acm@muc.de X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Resent-Date: Thu, 10 Dec 2009 09:47:33 -0500 X-BeenThere: bug-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:33461 Archived-At: Hi, Vivien! On Tue, Dec 01, 2009 at 03:35:38PM +0100, Vivien Oddou wrote: > in this code: > namespace n > { > int a = func float>(); // C-c C-s gives ((template-args-cont)) > } > void f() > { > int a = func float>(); // C-C Cs : ((defun-block-intro)) > int b = func< > int, // here too, refering to f() opening brace > float>(); > } > this is not normal. Indeed not. I've fixed this, and committed it to the head in Savannah. Here is the patch. Please try it out and let me know if anything isn't as it should be. Index: cc-engine.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/progmodes/cc-engine.el,v retrieving revision 1.79 diff -c -r1.79 cc-engine.el *** cc-engine.el 3 Dec 2009 16:02:10 -0000 1.79 --- cc-engine.el 10 Dec 2009 14:14:24 -0000 *************** *** 3743,3748 **** --- 3743,3799 ---- (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,3900 **** comment at the start of cc-engine.el for more info." (let ((start (point)) ! state ;; 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. 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. (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 (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))))) ;; We might want to extend this with more useful return values in ;; the future. --- 3812,3911 ---- comment at the start of cc-engine.el for more info." (let ((start (point)) ! 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. Used in `c-ssb-lit-begin' safe-pos-list ;; 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 ! ;; 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 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,8431 **** --- 8437,8443 ---- 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,9046 **** (back-to-indentation))) ;; FIXME: Should use c-add-stmt-syntax, but it's not yet ;; template aware. ! (c-add-syntax 'template-args-cont (point))) ;; CASE 5D.4: perhaps a multiple inheritance line? ((and (c-major-mode-is 'c++-mode) --- 9052,9058 ---- (back-to-indentation))) ;; FIXME: Should use c-add-stmt-syntax, but it's not yet ;; template aware. ! (c-add-syntax 'template-args-cont (point) placeholder)) ;; CASE 5D.4: perhaps a multiple inheritance line? ((and (c-major-mode-is 'c++-mode) *************** *** 9252,9261 **** ;; arglist that begins on the previous line. ((and c-recognize-<>-arglists (eq (char-before) ?<) (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))) ;; CASE 5Q: we are at a statement within a macro. (macro-start --- 9264,9274 ---- ;; 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) placeholder)) ;; CASE 5Q: we are at a statement within a macro. (macro-start *************** *** 9277,9290 **** ;; (CASE 6 has been removed.) ;; CASE 7: line is an expression, not a statement. Most ;; likely we are either in a function prototype or a function ! ;; call 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) ?{))) (cond ;; CASE 7A: we are looking at the arglist closing paren. --- 9290,9327 ---- ;; (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, 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) ?<))) (cond ;; CASE 7A: we are looking at the arglist closing paren. *************** *** 9381,9387 **** (c-forward-syntactic-ws) (point)) (c-point 'bonl))) ! (goto-char containing-sexp) (setq placeholder (c-point 'boi)) (if (and (c-safe (backward-up-list 1) t) (>= (point) placeholder)) --- 9418,9424 ---- (c-forward-syntactic-ws) (point)) (c-point 'bonl))) ! (goto-char containing-sexp) ; paren opening the arglist (setq placeholder (c-point 'boi)) (if (and (c-safe (backward-up-list 1) t) (>= (point) placeholder)) Index: cc-mode.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/progmodes/cc-mode.el,v retrieving revision 1.88 diff -c -r1.88 cc-mode.el *** cc-mode.el 5 Dec 2009 11:16:04 -0000 1.88 --- cc-mode.el 10 Dec 2009 14:14:24 -0000 *************** *** 541,559 **** (make-local-variable 'lookup-syntax-properties) (setq lookup-syntax-properties t))) ! ;; 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))) ;; 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 --- 541,555 ---- (make-local-variable 'lookup-syntax-properties) (setq lookup-syntax-properties t))) ! ;; 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) ! (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 > emacs 23.1.1 -- Alan Mackenzie (Nuremberg, Germany).