bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#5091: indentation in c++-mode


From: Alan Mackenzie
Subject: bug#5091: indentation in c++-mode
Date: Thu, 10 Dec 2009 14:37:17 +0000
User-agent: Mutt/1.5.9i

Hi, Vivien!

On Tue, Dec 01, 2009 at 03:35:38PM +0100, Vivien Oddou wrote:
> in this code:

> namespace n
> {
>     int a = func<int,
>                  float>();  // C-c C-s gives ((template-args-cont))
> }

> void f()
> {
>     int a = func<int,
>         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).





reply via email to

[Prev in Thread] Current Thread [Next in Thread]