;;; cplus-md.el --- C++ code editing commands for Emacs
-;;; Copyright (C) 1985, 1992 Free Software Foundation, Inc.
+
+;; Copyright (C) 1985, 1992, 1994, 1995 Free Software Foundation, Inc.
+
+;; Maintainer: Dave Detlefs <dld@cs.cmu.edu>
+;; Keywords: c
;; This file is part of GNU Emacs.
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-;; Maintainer: Dave Detlefs <dld@cs.cmu.edu>
-;; Keywords: c
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
(if c++-mode-syntax-table
()
- (setq c++-mode-syntax-table (copy-syntax-table c-mode-syntax-table))
+ (setq c++-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?\\ "\\" c++-mode-syntax-table)
+ (modify-syntax-entry ?/ ". 14" c++-mode-syntax-table)
+ (modify-syntax-entry ?* ". 23" c++-mode-syntax-table)
+ (modify-syntax-entry ?+ "." c++-mode-syntax-table)
+ (modify-syntax-entry ?- "." c++-mode-syntax-table)
+ (modify-syntax-entry ?= "." c++-mode-syntax-table)
+ (modify-syntax-entry ?% "." c++-mode-syntax-table)
+ (modify-syntax-entry ?< "." c++-mode-syntax-table)
+ (modify-syntax-entry ?> "." c++-mode-syntax-table)
+ (modify-syntax-entry ?& "." c++-mode-syntax-table)
+ (modify-syntax-entry ?| "." c++-mode-syntax-table)
+ (modify-syntax-entry ?\' "\"" c++-mode-syntax-table)
(modify-syntax-entry ?* ". 23b" c++-mode-syntax-table)
(modify-syntax-entry ?/ ". 124" c++-mode-syntax-table)
- (modify-syntax-entry ?\n ">" c++-mode-syntax-table))
+ (modify-syntax-entry ?\n ">" c++-mode-syntax-table)
+ (modify-syntax-entry ?\^m ">" c++-mode-syntax-table))
(defvar c++-continued-member-init-offset nil
"*Extra indent for continuation lines of member inits;
"*Indicates how far to indent an line following an empty argument
list. Nil indicates to just after the paren.")
+(defvar c++-imenu-generic-expression
+ (`
+ ((nil
+ (,
+ (concat
+ "^" ; beginning of line is required
+ "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+ "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
+ "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
+
+ "\\(" ; last type spec including */&
+ "[a-zA-Z0-9_:]+"
+ "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
+ "\\)?" ; if there is a last type spec
+ "\\(" ; name; take that into the imenu entry
+ "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
+ ; (may not contain * because then
+ ; "a::operator char*" would become "char*"!)
+ "\\|"
+ "\\([a-zA-Z0-9_:~]*::\\)?operator"
+ "[^a-zA-Z1-9_][^(]*" ; ...or operator
+ " \\)"
+ "[ \t]*([^)]*)[ \t\n]*[^ ;]" ; require something other than a ; after
+ ; the (...) to avoid prototypes. Can't
+ ; catch cases with () inside the parentheses
+ ; surrounding the parameters
+ ; (like "int foo(int a=bar()) {...}"
+
+ )) 6)
+ ("Class"
+ (, (concat
+ "^" ; beginning of line is required
+ "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+ "class[ \t]+"
+ "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+ "[ \t]*[:{]"
+ )) 2)
+;; Example of generic expression for finding prototypes, structs, unions, enums.
+;; Uncomment if you want to find these too. It will be a bit slower gathering
+;; the indexes.
+; ("Prototypes"
+; (,
+; (concat
+; "^" ; beginning of line is required
+; "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; type specs; there can be no
+; "\\([a-zA-Z0-9_:]+[ \t]+\\)?" ; more than 3 tokens, right?
+
+; "\\(" ; last type spec including */&
+; "[a-zA-Z0-9_:]+"
+; "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" ; either pointer/ref sign or whitespace
+; "\\)?" ; if there is a last type spec
+; "\\(" ; name; take that into the imenu entry
+; "[a-zA-Z0-9_:~]+" ; member function, ctor or dtor...
+; ; (may not contain * because then
+; ; "a::operator char*" would become "char*"!)
+; "\\|"
+; "\\([a-zA-Z0-9_:~]*::\\)?operator"
+; "[^a-zA-Z1-9_][^(]*" ; ...or operator
+; " \\)"
+; "[ \t]*([^)]*)[ \t\n]*;" ; require ';' after
+; ; the (...) Can't
+; ; catch cases with () inside the parentheses
+; ; surrounding the parameters
+; ; (like "int foo(int a=bar());"
+; )) 6)
+; ("Struct"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "struct[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+; ("Enum"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "enum[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+; ("Union"
+; (, (concat
+; "^" ; beginning of line is required
+; "\\(static[ \t]+\\)?" ; there may be static or const.
+; "\\(const[ \t]+\\)?"
+; "union[ \t]+"
+; "\\([a-zA-Z0-9_]+\\)" ; this is the string we want to get
+; "[ \t]*[{]"
+; )) 3)
+ ))
+ "Imenu generic expression for C++ mode. See `imenu-generic-expression'.")
-;;;###autoload
(defun c++-mode ()
"Major mode for editing C++ code. Very much like editing C code.
Expression and list commands understand all C++ brackets.
Extra indentation for line that is a label, or case or ``default:'', or
``public:'' or ``private:'', or ``protected:''.
c++-electric-colon
- If non-nil at invocation of c++-mode (t is the default) colon electricly
+ If non-nil at invocation of c++-mode (t is the default) colon electrically
indents.
c++-empty-arglist-indent
If non-nil, a function declaration or invocation which ends a line with a
no args if that value is non-nil."
(interactive)
(kill-all-local-variables)
+ ;; This code depends on the old C mode.
+ (require 'c-mode)
(use-local-map c++-mode-map)
(set-syntax-table c++-mode-syntax-table)
(setq major-mode 'c++-mode
(set (make-local-variable 'comment-end) "")
(set (make-local-variable 'comment-start-skip) "/\\*+ *\\|// *")
(set (make-local-variable 'comment-indent-function) 'c++-comment-indent)
- (set (make-local-variable 'paragraph-start) (concat "^$\\|" page-delimiter))
+ (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter))
(set (make-local-variable 'paragraph-separate) paragraph-start)
(set (make-local-variable 'paragraph-ignore-fill-prefix) t)
(set (make-local-variable 'require-final-newline) t)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
+ (make-local-variable 'imenu-generic-expression)
+ (setq imenu-generic-expression c++-imenu-generic-expression)
(run-hooks 'c++-mode-hook)
(if c++-electric-colon
(define-key c++-mode-map ":" 'electric-c++-terminator)))
;; So quickly rule out most other uses of colon
;; and do no indentation for them.
(and (eq last-command-char ?:)
- (not (looking-at "case[ \t]"))
- (save-excursion
- (forward-word 1)
- (skip-chars-forward " \t")
- (< (point) end))
- ;; Do re-indent double colons
- (save-excursion
- (end-of-line 1)
- (looking-at ":")))
+ (or (not (or (looking-at "case[ \t]")
+ (save-excursion
+ (forward-word 1)
+ (skip-chars-forward " \t")
+ (>= (point) end))))
+ ;; Do re-indent double colons
+ (save-excursion
+ (end-of-line 1)
+ (looking-at ":"))))
(progn
(beginning-of-defun)
(let ((pps (parse-partial-sexp (point) end)))
(backward-char 1))
(if (= (preceding-char) ?})
0
+ (if (= (preceding-char) ?\))
+ (forward-list -1))
(beginning-of-line) ; continued arg decls or member inits
(skip-chars-forward " \t")
(if (= (following-char) ?:)
;; Statement. Find previous non-comment character.
(goto-char indent-point)
(c++-backward-to-noncomment containing-sexp)
- (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?\{)))
+ (if (and (not (memq (preceding-char) '(0 ?\, ?\; ?\} ?\{)))
+ ;; But don't treat a line with a close-brace
+ ;; as a continuation. It is probably the
+ ;; end of an enum type declaration.
+ (save-excursion
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (not (= (following-char) ?}))))
;; This line is continuation of preceding line's statement;
;; indent c-continued-statement-offset more than the
;; previous line of the statement.
;; If no, find that first statement and indent like it.
(save-excursion
(forward-char 1)
- (while (progn (skip-chars-forward " \t\n")
- (looking-at
- (concat
- "#\\|/\\*\\|//"
- "\\|case[ \t]"
- "\\|[a-zA-Z0-9_$]*:[^:]"
- "\\|friend[ \t]")))
- ;; Skip over comments and labels following openbrace.
- (cond ((= (following-char) ?\#)
- (forward-line 1))
- ((looking-at "/\\*")
- (search-forward "*/" nil 'move))
- ((looking-at "//\\|friend[ \t]")
- (forward-line 1))
- (t
- (re-search-forward ":[^:]" nil 'move))))
- ;; The first following code counts
- ;; if it is before the line we want to indent.
- (and (< (point) indent-point)
- (current-column)))
+ (let ((colon-line-end 0))
+ (while (progn (skip-chars-forward " \t\n")
+ (looking-at
+ (concat
+ "#\\|/\\*\\|//"
+ "\\|case[ \t]"
+ "\\|[a-zA-Z0-9_$]*:[^:]"
+ "\\|friend[ \t]")))
+ ;; Skip over comments and labels following openbrace.
+ (cond ((= (following-char) ?\#)
+ (forward-line 1))
+ ((looking-at "/\\*")
+ (search-forward "*/" nil 'move))
+ ((looking-at "//\\|friend[ \t]")
+ (forward-line 1))
+ (t
+ (save-excursion (end-of-line)
+ (setq colon-line-end (point)))
+ (search-forward ":"))))
+ ;; The first following code counts
+ ;; if it is before the line we want to indent.
+ (and (< (point) indent-point)
+ (-
+ (if (> colon-line-end (point))
+ (- (current-indentation) c-label-offset)
+ (current-column))
+ ;; If prev stmt starts with open-brace, that
+ ;; open brace was offset by c-brace-offset.
+ ;; Compensate to get the column where
+ ;; an ordinary statement would start.
+ (if (= (following-char) ?\{) c-brace-offset 0)))))
;; If no previous statement,
;; indent it relative to line brace is on.
;; For open brace in column zero, don't let statement
((and
(search-backward "//" (max (c++-point-bol) lim) 'move)
(not (c++-within-string-p (point) opoint))))
- (t (beginning-of-line)
- (skip-chars-forward " \t")
- (if (looking-at "#")
- (setq stop (<= (point) lim))
- (setq stop t)
- (goto-char opoint)))))))
+ ;; No comment to be found.
+ ;; If there's a # command on this line,
+ ;; move back to it.
+ (t (beginning-of-line)
+ (skip-chars-forward " \t")
+ ;; But don't get fooled if we are already before the #.
+ (if (and (looking-at "#") (< (point) opoint))
+ (setq stop (<= (point) lim))
+ (setq stop t)
+ (goto-char opoint)))))))
(defun indent-c++-exp ()
"Indent each line of the C++ grouping following point."
(>= (car indent-stack) 0))
;; Line is on an existing nesting level.
;; Lines inside parens are handled specially.
- (if (/= (char-after (car contain-stack)) ?\{)
- (setq this-indent (car indent-stack))
- ;; Line is at statement level.
- ;; Is it a new statement? Is it an else?
- ;; Find last non-comment character before this line
- (save-excursion
- (setq at-else (looking-at "else\\W"))
- (setq at-brace (= (following-char) ?\{))
- (c++-backward-to-noncomment opoint)
- (if (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?: ?\{)))
- ;; Preceding line did not end in comma or semi;
- ;; indent this line c-continued-statement-offset
- ;; more than previous.
- (progn
- (c-backward-to-start-of-continued-exp
- (car contain-stack))
- (setq this-indent
- (+ c-continued-statement-offset
- (current-column)
- (if at-brace c-continued-brace-offset 0))))
- ;; Preceding line ended in comma or semi;
- ;; use the standard indent for this level.
- (if at-else
- (progn (c-backward-to-start-of-if opoint)
- (setq this-indent (current-indentation)))
- (setq this-indent (car indent-stack))))))
+ nil
;; Just started a new nesting level.
;; Compute the standard indent for this level.
- (let ((val (calculate-c++-indent
- (if (car indent-stack)
- (- (car indent-stack))))))
- (setcar indent-stack
- (setq this-indent val))))
+ (let (val)
+ (if (= (char-after (car contain-stack)) ?{)
+ (save-excursion
+ (goto-char (car contain-stack))
+ (setq val (calculate-c-indent-after-brace)))
+ (setq val (calculate-c++-indent
+ (if (car indent-stack)
+ (- (car indent-stack))))))
+ (setcar indent-stack val)))
+ ;; Adjust line indentation according to its predecessor.
+ (if (/= (char-after (car contain-stack)) ?\{)
+ (setq this-indent (car indent-stack))
+ ;; Line is at statement level.
+ ;; Is it a new statement? Is it an else?
+ ;; Find last non-comment character before this line
+ (save-excursion
+ (setq at-else (looking-at "else\\W"))
+ (setq at-brace (= (following-char) ?\{))
+ (c++-backward-to-noncomment opoint)
+ (if (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?: ?\{)))
+ ;; Preceding line did not end in comma or semi;
+ ;; indent this line c-continued-statement-offset
+ ;; more than previous.
+ (progn
+ (c-backward-to-start-of-continued-exp
+ (car contain-stack))
+ (setq this-indent
+ (+ c-continued-statement-offset
+ (current-column)
+ (if at-brace c-continued-brace-offset 0))))
+ ;; Preceding line ended in comma or semi;
+ ;; use the standard indent for this level.
+ (if at-else
+ (progn (c-backward-to-start-of-if opoint)
+ (setq this-indent (current-indentation)))
+ (setq this-indent (car indent-stack))))))
;; Adjust line indentation according to its contents
(if (looking-at "\\(public\\|private\\|protected\\):")
- (setq this-indent (- this-indent c-indent-level)))
- (if (or (looking-at "case[ \t]")
- (and (looking-at "[A-Za-z]")
- (save-excursion
- (forward-sexp 1)
- (looking-at ":[^:]"))))
- (setq this-indent (max 1 (+ this-indent c-label-offset))))
+ (setq this-indent (- this-indent c-indent-level))
+ (if (or (looking-at "case[ \t]")
+ (and (looking-at "[A-Za-z]")
+ (save-excursion
+ (forward-sexp 1)
+ (looking-at ":[^:]"))))
+ (setq this-indent (max 1 (+ this-indent c-label-offset)))))
(if (looking-at "friend[ \t]")
(setq this-indent (+ this-indent c++-friend-offset)))
(if (= (following-char) ?\})