home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-06-23 | 106.1 KB | 2,864 lines |
- ;;; c++-mode.el --- major mode for editing C++ (and C) code
-
- ;; Author: 1992 Barry A. Warsaw, Century Computing Inc. <bwarsaw@cen.com>
- ;; 1987 Dave Detlefs and Stewart Clamen
- ;; 1985 Richard M. Stallman
- ;; Maintainer: c++-mode-help@anthem.nlm.nih.gov
- ;; Created: a long, long, time ago. adapted from the original c-mode.el
- ;; Version: 2.353
- ;; Last Modified: 1993/06/23 13:58:52
- ;; Keywords: C++ C editing major-mode
-
- ;; Copyright (C) 1992, 1993 Free Software Foundation, Inc.
-
- ;; This file is part of GNU Emacs.
-
- ;; GNU Emacs is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 2, or (at your option)
- ;; any later version.
-
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; 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.
-
- ;; Introduction
- ;; ============
- ;; Do a "C-h m" in a c++-mode buffer for more information on
- ;; customizing c++-mode. To submit bug reports hit "C-c C-b" in a
- ;; c++-mode buffer. This runs the command c++-submit-bug-report and
- ;; automatically sets up the mail buffer with all the necessary
- ;; information. If you have other questions contact me at the
- ;; following address: c++-mode-help@anthem.nlm.nih.gov. Please don't
- ;; send bug reports to my personal account, I may not get it for a
- ;; long time.
-
- ;; Notes for Novice Users
- ;; ======================
- ;; c++-mode facilitates editing of C++ code by automatically handling
- ;; the indentation of lines of code in a manner very similar to c-mode
- ;; as distributed with GNU Emacs. Refer to the GNU Emacs manual,
- ;; chapter 21 for more information on "Editing Programs". In fact,
- ;; c++-mode (through its companion mode entry point c++-c-mode) can
- ;; also be used to edit both K&R and ANSI C code!
- ;;
- ;; To use c++-mode, add the following to your .emacs file. This
- ;; assumes you will use .cc or .C extensions for your C++ source:
- ;;
- ;; (autoload 'c++-mode "c++-mode" "C++ Editing Mode" t)
- ;; (autoload 'c++-c-mode "c++-mode" "C Editing Mode" t)
- ;; (setq auto-mode-alist
- ;; (append '(("\\.C$" . c++-mode)
- ;; ("\\.cc$" . c++-mode)
- ;; ("\\.c$" . c++-c-mode) ; to edit C code
- ;; ("\\.h$" . c++-c-mode) ; to edit C code
- ;; ) auto-mode-alist))
- ;;
- ;; If you want to use the default c-mode for editing C code, then just
- ;; omit the lines marked "to edit C code".
- ;;
- ;; Finally, you may want to customize certain c++-mode variables. The
- ;; best place to do this is in the mode hook variable called
- ;; c++-mode-hook. Again, see the Emacs manual, chapter 21 for more
- ;; information.
-
- ;; Important Note about Escapes in Comments, and Performance
- ;; =========================================================
- ;; You may notice that certain characters, when typed in comment
- ;; regions, get escaped with a backslash. This is a workaround for
- ;; bugs in Emacs' syntax parsing algorithms. In brief, syntax parsing
- ;; in Emacs 18 and derivatives is broken because syntax tables are not
- ;; rich enough to support more than 1 comment style per mode (as C++
- ;; requires). The result is that Emacs will sometimes choke on
- ;; unbalanced parentheses and single quotes in comments. Please do a
- ;; "C-h v c++-untame-characters" for more information.
- ;;
- ;; This problem affect both the accuracy and performance of c++-mode
- ;; because some parsing must be performed in Emacs lisp instead of
- ;; relying on the C primitives. In general, I've chosen accuracy over
- ;; performance, but have worked hard to give moderately acceptable
- ;; speed in all but the most uncommon situations. You will most likely
- ;; notice c++-mode slowing when you're editing a file of preprocessor
- ;; commands, or inside long functions or class definitions.
- ;; Optimization is an ongoing concern, but the real solution is to fix
- ;; Emacs.
- ;;
- ;; As of release 19.4, Lucid Emacs is distributed with the fixes in
- ;; place, and c++-mode will automatically take advantage of them so
- ;; none of the above applies to you. Similar patches will be part of
- ;; FSF GNU Emacs 19. Some patches for GNU Emacs 18 have been released
- ;; on the beta site, but they are unsupported. Email for more
- ;; information.
-
- ;; Beta Testers Mailing List
- ;; =========================
- ;; Want to be a c++-mode victim, er, beta-tester? Send add/drop
- ;; requests to c++-mode-victims-request@anthem.nlm.nih.gov.
- ;; Discussions go to c++-mode-victims@anthem.nlm.nih.gov, but bug
- ;; reports and such should still be sent to c++-mode-help only.
- ;;
- ;; Many, many thanks go out to all the folks on the beta test list.
- ;; Without their patience, testing, insight, and code contribution,
- ;; c++-mode.el would be a far inferior package.
-
- ;; Getting c++-mode.el
- ;; ===================
- ;; The latest public release version of this file should always be
- ;; available for anonymous ftp on the Emacs lisp archive machine. The
- ;; path to the file is:
- ;;
- ;; archive.cis.ohio-state.edu:pub/gnu/emacs/elisp-archive/modes/c++-mode.el.Z
- ;;
- ;; For those of you without anon-ftp access, you can use the DEC's
- ;; ftpmail'er at the address ftpmail@decwrl.dec.com. Send the
- ;; following message in the body of your mail to that address to get
- ;; c++-mode:
- ;;
- ;; reply <a valid net address back to you>
- ;; connect archive.cis.ohio-state.edu
- ;; binary
- ;; uuencode
- ;; chdir pub/gnu/emacs/elisp-archive/modes
- ;; get c++-mode.el.Z
- ;;
- ;; or just send the message "help" for more information on ftpmail.
- ;; Response times will vary with the number of requests in the queue.
-
- ;; LCD Archive Entry:
- ;; c++-mode|Barry A. Warsaw|c++-mode-help@anthem.nlm.nih.gov|
- ;; Mode for editing C++, and ANSI/K&R C code (was Detlefs' c++-mode.el)|
- ;; 23-Jun-1993|2.353|~/modes/c++-mode.el.Z|
-
- ;;; Code:
-
- ;; some people may not have c-mode loaded in by default. c++-mode.el
- ;; unfortunately still depends on distrib c-mode. c-mode doesn't
- ;; provide itself so this hack is best known way to ensure its loaded
- (or (fboundp 'c-mode)
- (load "c-mode" nil t))
-
-
- ;; ======================================================================
- ;; user definable variables
- ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-
- (defconst c++-emacs-features
- (let ((mse-spec 'no-dual-comments)
- (scanner 'v18))
- ;; vanilla GNU18/Epoch 4 uses default values
- (if (= 8 (length (parse-partial-sexp (point) (point))))
- ;; we know we're using v19 style dual-comment specifications.
- ;; All Lemacsen use 8-bit modify-syntax-entry flags, as do all
- ;; patched FSF19, GNU18, Epoch4's. Only vanilla FSF19 uses
- ;; 1-bit flag. Lets be as smart as we can about figuring this
- ;; out.
- (let ((table (copy-syntax-table)))
- (modify-syntax-entry ?a ". 12345678" table)
- (if (= (logand (lsh (aref table ?a) -16) 255) 255)
- (setq mse-spec '8-bit)
- (setq mse-spec '1-bit))
- ;; we also know we're using a quicker, built-in comment
- ;; scanner, but we don't know if its old-style or new.
- ;; Fortunately we can ask emacs directly
- (if (fboundp 'forward-comment)
- (setq scanner 'v19)
- (setq scanner 'old-v19))))
- ;; now cobble up the necessary list
- (list mse-spec scanner))
- "A list of needed features extant in the Emacs you are using.
- There are many flavors of Emacs out on the net, each with different
- features supporting those needed by c++-mode. Here's the current
- known list, along with the values for this variable:
-
- Vanilla GNU 18/Epoch 4: (no-dual-comments v18)
- GNU 18/Epoch 4 (patch1): (8-bit old-v19)
- GNU 18/Epoch 4 (patch2): (8-bit v19)
- Lemacs 19.4 - 19.7: (8-bit old-v19)
- Lemacs 19.8 and over: (8-bit v19)
- FSF 19: (1-bit v19)
- FSF 19 (patched): (8-bit v19)")
-
- (defvar c++-mode-abbrev-table nil
- "Abbrev table in use in c++-mode buffers.")
- (define-abbrev-table 'c++-mode-abbrev-table ())
-
- (defvar c++-mode-map ()
- "Keymap used in c++-mode.")
- (if c++-mode-map
- ()
- (setq c++-mode-map (make-sparse-keymap))
- (define-key c++-mode-map "\C-j" 'reindent-then-newline-and-indent)
- (define-key c++-mode-map "\C-m" 'newline-and-indent)
- (define-key c++-mode-map "{" 'c++-electric-brace)
- (define-key c++-mode-map "}" 'c++-electric-brace)
- (define-key c++-mode-map ";" 'c++-electric-semi)
- (define-key c++-mode-map "#" 'c++-electric-pound)
- (define-key c++-mode-map "\e\C-h" 'mark-c-function)
- (define-key c++-mode-map "\e\C-q" 'c++-indent-exp)
- (define-key c++-mode-map "\t" 'c++-indent-command)
- (define-key c++-mode-map "\C-c\C-i" 'c++-insert-header)
- (define-key c++-mode-map "\C-c\C-\\" 'c++-macroize-region)
- (define-key c++-mode-map "\C-c\C-c" 'c++-comment-region)
- (define-key c++-mode-map "\C-c\C-u" 'c++-uncomment-region)
- (define-key c++-mode-map "\C-c\C-x" 'c++-match-paren)
- (define-key c++-mode-map "\e\C-a" 'c++-beginning-of-defun)
- (define-key c++-mode-map "\e\C-e" 'c++-end-of-defun)
- (define-key c++-mode-map "\e\C-x" 'c++-indent-defun)
- (define-key c++-mode-map "/" 'c++-electric-slash)
- (define-key c++-mode-map "*" 'c++-electric-star)
- (define-key c++-mode-map ":" 'c++-electric-colon)
- (define-key c++-mode-map "\177" 'c++-electric-delete)
- (define-key c++-mode-map "\C-c\C-t" 'c++-toggle-auto-hungry-state)
- (define-key c++-mode-map "\C-c\C-h" 'c++-toggle-hungry-state)
- (define-key c++-mode-map "\C-c\C-a" 'c++-toggle-auto-state)
- (if (memq 'v18 c++-emacs-features)
- (progn
- (define-key c++-mode-map "\C-c'" 'c++-tame-comments)
- (define-key c++-mode-map "'" 'c++-tame-insert)
- (define-key c++-mode-map "[" 'c++-tame-insert)
- (define-key c++-mode-map "]" 'c++-tame-insert)
- (define-key c++-mode-map "(" 'c++-tame-insert)
- (define-key c++-mode-map ")" 'c++-tame-insert)))
- (define-key c++-mode-map "\C-c\C-b" 'c++-submit-bug-report)
- (define-key c++-mode-map "\C-c\C-v" 'c++-version)
- ;; these are necessary because default forward-sexp and
- ;; backward-sexp don't automatically let-bind
- ;; parse-sexp-ignore-comments, which is needed for them to work
- ;; properly in a C++ buffer.
- (define-key c++-mode-map "\e\C-f" 'c++-forward-sexp)
- (define-key c++-mode-map "\e\C-b" 'c++-backward-sexp)
- )
-
- (defvar c++-mode-syntax-table nil
- "Syntax table used in c++-mode buffers.")
- (defvar c++-c-mode-syntax-table nil
- "Syntax table used in c++-c-mode buffers.")
-
- (if c++-mode-syntax-table
- ()
- (setq c++-mode-syntax-table (make-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 ?\' "\"" c++-mode-syntax-table)
- ;; comment syntax
- (cond
- ((memq '8-bit c++-emacs-features)
- ;; Lucid emacs has the best implementation
- (modify-syntax-entry ?/ ". 1456" c++-mode-syntax-table)
- (modify-syntax-entry ?* ". 23" c++-mode-syntax-table)
- (modify-syntax-entry ?\n "> b" c++-mode-syntax-table))
- ((memq '1-bit c++-emacs-features)
- ;; FSF19 has sub-optimal, but workable implementation
- ;; Some strange behavior may be encountered. LOBBY FSF!
- (modify-syntax-entry ?/ ". 124" c++-mode-syntax-table)
- (modify-syntax-entry ?* ". 23b" c++-mode-syntax-table)
- (modify-syntax-entry ?\n ">" c++-mode-syntax-table))
- (t
- ;; Vanilla GNU18 is just plain busted. We'll do the best we can,
- ;; but some strange behavior may be encountered. PATCH or UPGRADE!
- (modify-syntax-entry ?/ ". 124" c++-mode-syntax-table)
- (modify-syntax-entry ?* ". 23" c++-mode-syntax-table)
- (modify-syntax-entry ?\n ">" c++-mode-syntax-table))
- ))
-
- (if c++-c-mode-syntax-table
- ()
- (setq c++-c-mode-syntax-table (make-syntax-table))
- (modify-syntax-entry ?\\ "\\" c++-c-mode-syntax-table)
- (modify-syntax-entry ?+ "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?- "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?= "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?% "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?< "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?> "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?& "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?| "." c++-c-mode-syntax-table)
- (modify-syntax-entry ?\' "\"" c++-c-mode-syntax-table)
- (modify-syntax-entry ?/ ". 14" c++-c-mode-syntax-table)
- (modify-syntax-entry ?* ". 23" c++-c-mode-syntax-table)
- )
-
- (defvar c++-tab-always-indent
- (if (boundp 'c-tab-always-indent) c-tab-always-indent t)
- "*Controls the operation of the TAB key.
- If t (the default), always just indent the current line. If nil,
- indent the current line only if point is at the left margin or in the
- line's indentation; otherwise insert a tab. If not-nil-or-t, then tab
- is inserted only within literals (comments and strings) and inside
- preprocessor directives, but line is always reindented.")
- (defvar c++-always-arglist-indent-p nil
- "*Control indentation of continued arglists.
- When non-nil, arglists continued on subsequent lines will always
- indent `c++-empty-arglist-indent' spaces, otherwise, they will indent to
- just under previous line's argument indentation.")
- (defvar c++-block-close-brace-offset 0
- "*Extra indentation given to close braces which close a block.
- This variable can be either an integer or a list. If an integer, it
- describes the extra offset given a block closing brace (and a closing
- paren if `c++-paren-as-block-close-p' is non-nil), treating all
- closing parens the same. If a list of the form (OTHERS . TOPLEVEL),
- OTHERS is an integer describing the offset given to all but top-level
- (e.g. function) closing braces, while TOPLEVEL is an integer
- describing offset given only to braces which close top-level
- constructs.")
- (defvar c++-paren-as-block-close-p nil
- "*Treat a parenthesis which is the first non-whitespace on a line as
- a paren which closes a block. When non-nil, `c-indent-level' is
- subtracted, and `c++-block-close-brace-offset' is added to the line's
- offset.")
- (defvar c++-continued-member-init-offset nil
- "*Extra indent for continuation lines of member inits; nil means to align
- with previous initializations rather than with the colon on the first line.")
- (defvar c++-member-init-indent 0
- "*Indentation level of member initializations in function declarations.")
- (defvar c++-friend-offset -4
- "*Offset of C++ friend class declarations relative to member declarations.")
- (defvar c++-access-specifier-offset c-label-offset
- "*Extra indentation given to public, protected, and private labels.")
- (defvar c++-empty-arglist-indent nil
- "*Indicates how far to indent a line following an empty argument list.
- Nil means indent to just after the paren.")
- (defvar c++-comment-only-line-offset 0
- "*Indentation offset for line which contains only C or C++ style comments.
- This variable can take either a single integer or a list of integers.
- If a single integer this is the extra indentation offset to apply to
- all comment-only lines, except those which start in column zero. If a
- list is used, the first integer is for all non-column-zero
- comment-only lines and the second integer is for all column-zero
- lines. You can also use a list containing only 1 integer, in which
- case, this value is used for all comment-only lines. For example:
-
- value meaning
- ===== =======
- 0 comment-only lines do not indent
- 4 non-col0 lines indent 4 spaces, col0 lines don't indent
- '(4) all comment-only lines indent 4 spaces
- '(4 1) non-col0 lines indent 4 spaces, col0 lines indent 1 space")
-
- (defvar c++-C-block-comments-indent-p nil
- "*4 styles of C block comments are supported. If this variable is nil,
- then styles 1-3 are supported. If this variable is non-nil, style 4 is
- supported.
- style 1: style 2: style 3: style 4:
- /* /* /* /*
- blah * blah ** blah blah
- blah * blah ** blah blah
- */ */ */ */
- ")
- (defvar c++-cleanup-list nil
- "*List of various C++ constructs to ``clean up''.
- These cleanups only take place when the auto-newline feature is turned
- on, as evidenced by the `/a' or `/ah' appearing next to the mode name.
-
- Current legal values are:
- `brace-else-brace' -- clean up ``} else {'' constructs by placing entire
- construct on a single line. This cleanup only
- takes place when there is nothing but white
- space between the braces and the else.
- `empty-defun-braces' -- cleans up empty C++ function braces by
- placing them on the same line.
- `defun-close-semi' -- cleans up the terminating semi-colon on class
- definitions and functions by placing the semi
- on the same line as the closing brace.")
- (defvar c++-hanging-braces t
- "*Controls the insertion of newlines before open (left) braces.
- This variable only has effect when auto-newline is on, as evidenced by
- the `/a' or `/ah' appearing next to the mode name. If nil, open
- braces do not hang (i.e. a newline is inserted before all open
- braces). If t, all open braces hang -- no newline is inserted before
- open braces. If not nil or t, newlines are only inserted before
- top-level open braces; all other braces hang.")
- (defvar c++-hanging-member-init-colon 'before
- "*Defines how colons which introduce member initializations are formatted.
- Legal values are:
- t -- no newlines inserted before or after colon
- nil -- newlines inserted before and after colon
- `after' -- newlines inserted only after colon
- `before` -- newlines inserted only before colon")
- (defvar c++-auto-hungry-initial-state 'none
- "*Initial state of auto/hungry features when buffer is first visited.
- Legal values are:
- `none' -- no auto-newline and no hungry-delete-key.
- `auto-only' -- auto-newline, but no hungry-delete-key.
- `hungry-only' -- no auto-newline, but hungry-delete-key.
- `auto-hungry' -- both auto-newline and hungry-delete-key enabled.
- Nil is synonymous for `none' and t is synonymous for `auto-hungry'.")
-
- (defvar c++-auto-hungry-toggle t
- "*Enable/disable toggling of auto/hungry features.
- Legal values are:
- `none' -- auto-newline and hungry-delete-key cannot be enabled.
- `auto-only' -- only auto-newline feature can be toggled.
- `hungry-only' -- only hungry-delete-key feature can be toggled.
- `auto-hungry' -- both auto-newline and hungry-delete-key can be toggled.
- Nil is synonymous for `none' and t is synonymous for `auto-hungry'.")
-
- (defvar c++-relative-offset-p t
- "*Control the calculation for indentation.
- When non-nil (the default), indentation is calculated relative to the
- first statement in the block. When nil, the indentation is calculated
- without regard to how the first statement is indented.")
-
- (defvar c++-untame-characters (and (memq 'v18 c++-emacs-features) '(?\'))
- "*Utilize a backslashing workaround of an Emacs syntax parsing bug.
- If non-nil, this variable should contain a list of characters which
- will be prepended by a backslash in comment regions. By default, the
- list contains only the most troublesome character, the single quote.
- To be completely safe, set this variable to:
-
- '(?\( ?\) ?\' ?\{ ?\} ?\[ ?\])
-
- This is the full list of characters which can potentially cause
- problems if they exist unbalanced within comments. Setting this
- variable to nil will defeat this feature, but be forewarned! Such
- un-escaped characters in comment regions can potentially break many
- things such as some indenting and blinking of parenthesis.
-
- Note further that only the default set of characters will be escaped
- automatically as they are typed. But, executing `c++-tame-comments'
- (\\[c++-tame-comments]) will escape all characters which are members
- of this set, and which are found in comments throughout the file.
-
- Finally, c++-mode can tell if you're running a patched Emacs. If so,
- taming characters isn't necessary and this variable is automatically
- set to nil.")
-
- (defvar c++-default-macroize-column 78
- "*Column to insert backslashes.")
- (defvar c++-special-indent-hook nil
- "*Hook for user defined special indentation adjustments.
- This hook gets called after a line is indented by the mode. By
- supplying a hook, you can make adjustments to the line's standard
- indentation. If you do use this hook, you will likely need to also
- set `c++-relative-offset-p' to nil. The call to this hook is wrapped in
- a `save-excursion' so you don't need to worry about restoring point and
- mark inside the hook function.")
- (defvar c++-delete-function 'backward-delete-char-untabify
- "*Function called by `c++-electric-delete' when deleting a single char.")
- (defvar c++-electric-pound-behavior nil
- "*List of behaviors for electric pound insertion.
- Only currently supported behavior is `alignleft'.")
- (defvar c++-backscan-limit 2000
- "*Limit in characters for looking back while skipping syntactic ws.
- If you typically write really big methods, and start noticing
- incorrect indentations, try cranking this value up. The larger this
- value is, though, the slower parts of c++-mode can become. Setting
- this variable to nil defeats backscan limits.")
-
- ;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ;; NO USER DEFINABLE VARIABLES BEYOND THIS POINT
- ;;
- (defvar c++-hungry-delete-key nil
- "Internal state of hungry delete key feature.")
- (defvar c++-auto-newline nil
- "Internal state of auto newline feature.")
-
- (make-variable-buffer-local 'c++-auto-newline)
- (make-variable-buffer-local 'c++-hungry-delete-key)
-
- (defconst c++-access-key "\\<\\(public\\|protected\\|private\\)\\>:"
- "Regexp which describes access specification keywords.")
- (defconst c++-class-key
- (concat
- "\\(\\(extern\\|typedef\\)\\s +\\)?"
- "\\(template\\s *<[^>]*>\\s *\\)?"
- "\\<\\(class\\|struct\\|union\\)\\>")
- "Regexp which describes a class declaration, including templates.")
- (defconst c++-inher-key
- (concat "\\(\\<static\\>\\s +\\)?"
- c++-class-key
- "[ \t]+\\(\\(\\w\\|_\\)+[ \t]*:[ \t]*\\)?")
- "Regexp which describes a class inheritance declaration.")
-
-
- ;; ======================================================================
- ;; c++-mode main entry point
- ;; ======================================================================
- (defun c++-mode ()
- "Major mode for editing C++ code. 2.353
- To submit a problem report, enter `\\[c++-submit-bug-report]' from a
- c++-mode buffer. This automatically sets up a mail buffer with
- version information already added. You just need to add a description
- of the problem and send the message.
-
- 1. Very much like editing C code,
- 2. Expression and list commands understand all C++ brackets,
- 3. Tab at left margin indents for C++ code,
- 4. Both C++ and C style block comments are recognized,
- 5. Paragraphs are separated by blank lines only,
- 6. Hungry delete key and auto newline features are optional.
-
- IMPORTANT NOTE: You may notice that some characters (by default, only
- single quote) will get escaped with a backslash when typed in a
- comment region. This is a necessary workaround of a bug present in
- GNU Emacs 18 and derivatives. Enter `\\[describe-variable] c++-untame-characters RET'
- for more information. If you are running a patched Emacs, no
- characters will be escaped in comment regions, and many functions will
- run much faster.
-
- Key bindings:
- \\{c++-mode-map}
-
- These variables control indentation style. Those with names like
- c-<thing> are inherited from c-mode. Those with names like
- c++-<thing> are unique for this mode, or have extended functionality
- from their c-mode cousins.
-
- c-argdecl-indent
- Indentation level of declarations of C function arguments.
- c-brace-imaginary-offset
- An open brace following other text is treated as if it were
- this far to the right of the start of its line.
- c-brace-offset
- Extra indentation for line if it starts with an open brace.
- c-continued-brace-offset
- Extra indentation given to a brace that starts a substatement.
- This is in addition to `c-continued-statement-offset'.
- c-continued-statement-offset
- Extra indentation given to a substatement, such as the
- then-clause of an if or body of a while.
- c-indent-level
- Indentation of C statements within surrounding block.
- The surrounding block's indentation is the indentation
- of the line on which the open-brace appears.
- c-label-offset
- Extra indentation for line that is a label, or case or ``default:''
-
- c++-C-block-comments-indent-p
- Style of C block comments to support.
- c++-access-specifier-offset
- Extra indentation given to public, protected, and private keyword lines.
- c++-always-arglist-indent-p
- Control indentation of continued arglists. When non-nil, arglists
- continued on subsequent lines will always indent
- `c++-empty-arglist-indent' spaces, otherwise, they will indent to
- just under previous line's argument indentation.
- c++-auto-hungry-initial-state
- Initial state of auto/hungry feature when a C++ buffer is first visited.
- c++-auto-hungry-toggle
- Enable/disable toggling of auto/hungry features.
- c++-backscan-limit
- Limit in characters for looking back while skipping syntactic
- whitespace. This variable is only used in an un-patched Emacs to
- help improve performance at the expense of some accuracy. Patched
- Emacses are both fast and accurate.
- c++-block-close-brace-offset
- Extra indentation give to braces which close a block.
- c++-cleanup-list
- A list of construct ``clean ups'' which c++-mode will perform when
- auto-newline feature is on. Current legal values are:
- `brace-else-brace', `empty-defun-braces', `defun-close-semi'.
- c++-comment-only-line-offset
- Extra indentation for a line containing only a C or C++ style
- comment. Can be an integer or list, specifying the various styles
- of comment-only line special indentations.
- c++-continued-member-init-offset
- Extra indentation for continuation lines of member initializations; nil
- means to align with previous initializations rather than with the colon.
- c++-default-macroize-column
- Column to insert backslashes when macroizing a region.
- c++-delete-function
- Function called by `c++-electric-delete' when deleting a single char.
- c++-electric-pound-behavior
- List of behaviors for electric pound insertion.
- c++-empty-arglist-indent
- Extra indentation to apply to a line following an empty argument
- list. nil means to line it up with the left paren.
- c++-friend-offset
- Offset of C++ friend class declarations relative to member declarations.
- c++-hanging-braces
- Controls open brace hanging behavior when using auto-newline feature.
- nil says no braces hang, t says all open braces hang. non-nil-or-t
- means top-level open braces don't hang, all others do.
- c++-hanging-member-init-colon
- Defines how colons which introduce member initialization lists are
- formatted. t means no newlines are inserted either before or after
- the colon. nil means newlines are inserted both before and after
- the colon. `before' inserts newlines only before the colon, and
- `after' inserts newlines only after colon.
- c++-member-init-indent
- Indentation level of member initializations in function declarations,
- if they are on a separate line beginning with a colon.
- c++-paren-as-block-close-p
- If non-nil, treat a parenthesis which is the first non-whitespace
- on a line as a paren which closes a block (i.e. treat it similar
- to right curly brace).
- c++-relative-offset-p
- Control the calculation for indentation. When non-nil (the
- default), indentation is calculated relative to the first
- statement in the block. When nil, the indentation is calculated
- without regard to how the first statement is indented. Useful when
- using a `c++-special-indent-hook'.
- c++-special-indent-hook
- Hook for user defined special indentation adjustments. You can use
- this hook, which gets called after a line is indented by the mode,
- to customize indentations of the line.
- c++-tab-always-indent
- Controls the operation of the TAB key. t means always just indent
- the current line. nil means indent the current line only if point
- is at the left margin or in the line's indentation; otherwise
- insert a tab. If not-nil-or-t, then tab is inserted only within
- literals (comments and strings) and inside preprocessor
- directives, but the line is always reindented. Default is value
- for `c-tab-always-indent'.
- c++-untame-characters
- When non-nil, inserts backslash escapes before certain untamed
- characters in comment regions. It is recommended that you keep the
- default setting to workaround a nasty Emacs bug, unless you are
- running a patched Emacs.
-
- Auto-newlining is no longer an all or nothing proposition. In my
- opinion, I don't believe it is possible to implement a perfect
- auto-newline algorithm. Sometimes you want it and sometimes you don't.
- So now auto-newline (and its companion feature, hungry-delete-key) can
- be toggled on and off on the fly. Hungry-delete-key is the optional
- behavior of the delete key so that, when enabled, hitting the delete
- key once consumes all preceding whitespace, unless point is within a
- literal (defined as a C or C++ comment, or string). Inside literals,
- and with hungry-delete-key disabled, the delete key just calls the
- function in variable `c++-delete-function'.
-
- Selection and toggling of these features is controlled by the
- variables `c++-auto-hungry-initial-state' and `c++-auto-hungry-toggle'.
- Legal values for both variables are:
-
- `none' (or nil) -- no auto-newline or hungry-delete-key.
- `auto-only' -- function affects only auto-newline feature.
- `hungry-only' -- function affects only hungry-delete-key feature.
- `auto-hungry' (or t) -- function affects both features.
-
- Thus if `c++-auto-hungry-initial-state' is `hungry-only', then only
- hungry-delete-key feature is turned on when the buffer is first
- visited. If `c++-auto-hungry-toggle' is `auto-hungry', and both
- auto-newline and hungry-delete-key features are on, then hitting
- `\\[c++-toggle-auto-hungry-state]' will toggle both features. Hitting
- `\\[c++-toggle-hungry-state]' will always toggle hungry-delete-key
- feature and hitting `\\[c++-toggle-auto-state]' will always toggle
- auto-newline feature, regardless of the value of
- `c++-auto-hungry-toggle'.
-
- Settings for K&R, BSD, and Stroustrup indentation styles are
- c-indent-level 5 8 4
- c-continued-statement-offset 5 8 4
- c-continued-brace-offset 0
- c-brace-offset -5 -8 0
- c-brace-imaginary-offset 0
- c-argdecl-indent 0 8 4
- c-label-offset -5 -8 -4
- c++-access-specifier-offset -5 -8 -4
- c++-empty-arglist-indent 4
- c++-friend-offset 0
-
- Turning on C++ mode calls the value of the variable `c++-mode-hook' with
- no args, if that value is non-nil."
- (interactive)
- (kill-all-local-variables)
- (use-local-map c++-mode-map)
- (set-syntax-table c++-mode-syntax-table)
- (setq major-mode 'c++-mode
- mode-name "C++"
- local-abbrev-table c++-mode-abbrev-table)
- (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) nil)
- ;;
- (set (make-local-variable 'indent-line-function) 'c++-indent-line)
- (set (make-local-variable 'comment-start) "// ")
- (set (make-local-variable 'comment-end) "")
- (set (make-local-variable 'comment-column) 32)
- (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|// *")
- (set (make-local-variable 'comment-indent-hook) 'c++-comment-indent)
- ;; hack auto-hungry designators into mode-line-format
- (if (listp mode-line-format)
- (setq mode-line-format
- (let ((modeline nil))
- (mapcar
- (function
- (lambda (element)
- (setq modeline
- (append modeline
- (if (eq element 'mode-name)
- '(mode-name (c++-hungry-delete-key
- (c++-auto-newline "/ah" "/h")
- (c++-auto-newline "/a")))
- (list element))))))
- mode-line-format)
- modeline)))
- (run-hooks 'c++-mode-hook)
- (c++-set-auto-hungry-state
- (memq c++-auto-hungry-initial-state '(auto-only auto-hungry t))
- (memq c++-auto-hungry-initial-state '(hungry-only auto-hungry t))))
-
- (defun c++-c-mode ()
- "Major mode for editing K&R and ANSI C code. 2.353
- This mode is based on c++-mode. Documentation for this mode is
- available by doing a `\\[describe-function] c++-mode'."
- (interactive)
- (c++-mode)
- (setq major-mode 'c++-c-mode
- mode-name "C"
- local-abbrev-table c-mode-abbrev-table)
- (setq comment-start "/* "
- comment-end " */")
- ;; some syntax differences are necessary for C vs. C++
- (set-syntax-table c++-c-mode-syntax-table)
- (run-hooks 'c++-c-mode-hook))
-
- (defun c++-comment-indent ()
- "Used by `indent-for-comment' to decide how much to indent a comment
- in C++ code based on its context."
- (if (looking-at "^\\(/\\*\\|//\\)")
- 0 ; Existing comment at bol stays there.
- (save-excursion
- (skip-chars-backward " \t")
- (max
- ;; leave at least one space on non-empty lines.
- (if (zerop (current-column))
- 0
- (1+ (current-column)))
- ;; use comment-column if previous line is comment only line
- ;; indented to the left of comment-column
- (save-excursion
- (beginning-of-line)
- (if (not (bobp)) (forward-line -1))
- (skip-chars-forward " \t")
- (if (looking-at "/\\*\\|//")
- (if (< (current-column) comment-column)
- comment-column
- (current-column))
- 0))
- (let ((cur-pt (point)))
- (beginning-of-line 0)
- ;; If previous line had a comment, use it's indent
- (if (re-search-forward comment-start-skip cur-pt t)
- (progn
- (goto-char (match-beginning 0))
- (current-column))
- comment-column)))))) ; otherwise indent at comment column.
-
-
- ;; ======================================================================
- ;; most command level (interactive) and related
- ;; ======================================================================
- (defun c++-set-auto-hungry-state (auto-p hungry-p)
- "Set auto/hungry to state indicated by AUTO-P and HUNGRY-P.
- Update mode line to indicate state to user."
- (setq c++-auto-newline auto-p
- c++-hungry-delete-key hungry-p)
- (set-buffer-modified-p (buffer-modified-p)))
-
- (defun c++-toggle-auto-state (arg)
- "Toggle auto-newline feature.
- This function ignores `c++-auto-hungry-toggle' variable. Optional
- numeric ARG, if supplied turns on auto-newline when positive, turns
- off auto-newline when negative and toggles when zero."
- (interactive "P")
- (let ((auto (cond
- ((not arg)
- (not c++-auto-newline))
- ((zerop (setq arg (prefix-numeric-value arg)))
- (not c++-auto-newline))
- ((< arg 0) nil)
- (t t))))
- (c++-set-auto-hungry-state auto c++-hungry-delete-key)))
-
- (defun c++-toggle-hungry-state (arg)
- "Toggle hungry-delete-key feature.
- This function ignores `c++-auto-hungry-toggle' variable. Optional
- numeric ARG, if supplied turns on hungry-delete-key when positive,
- turns off hungry-delete-key when negative and toggles when zero."
- (interactive "P")
- (let ((hungry (cond
- ((not arg)
- (not c++-hungry-delete-key))
- ((zerop (setq arg (prefix-numeric-value arg)))
- (not c++-hungry-delete-key))
- ((< arg 0) nil)
- (t t))))
- (c++-set-auto-hungry-state c++-auto-newline hungry)))
-
- (defun c++-toggle-auto-hungry-state (arg)
- "Toggle auto-newline and hungry-delete-key features.
- Actual toggling of these features is controlled by
- `c++-auto-hungry-toggle' variable.
-
- Optional argument has the following meanings when supplied:
- Universal argument \\[universal-argument]
- resets features to c++-auto-hungry-initial-state.
- negative number
- turn off both auto-newline and hungry-delete-key features.
- positive number
- turn on both auto-newline and hungry-delete-key features.
- zero
- toggle both features regardless of `c++-auto-hungry-toggle-p'."
- (interactive "P")
- (let* ((numarg (prefix-numeric-value arg))
- (apl (list 'auto-only 'auto-hungry t))
- (hpl (list 'hungry-only 'auto-hungry t))
- (auto (cond
- ((not arg)
- (if (memq c++-auto-hungry-toggle apl)
- (not c++-auto-newline)
- c++-auto-newline))
- ((listp arg)
- (memq c++-auto-hungry-initial-state apl))
- ((zerop numarg)
- (not c++-auto-newline))
- ((< arg 0) nil)
- (t t)))
- (hungry (cond
- ((not arg)
- (if (memq c++-auto-hungry-toggle hpl)
- (not c++-hungry-delete-key)
- c++-hungry-delete-key))
- ((listp arg)
- (memq c++-auto-hungry-initial-state hpl))
- ((zerop numarg)
- (not c++-hungry-delete-key))
- ((< arg 0) nil)
- (t t))))
- (c++-set-auto-hungry-state auto hungry)))
-
- (defun c++-tame-insert (arg)
- "Safely inserts certain troublesome characters in comment regions.
- Because of syntax bugs in Emacs, characters with string or parenthesis
- syntax must be escaped with a backslash or lots of things get messed
- up. Unfortunately, setting `parse-sexp-ignore-comments' to non-nil does
- not fix the problem, but this function is unnecessary if you are
- running a patched Emacs.
-
- See also the variable `c++-untame-characters'."
- (interactive "p")
- (if (and (memq last-command-char c++-untame-characters)
- (memq (c++-in-literal) '(c c++)))
- (insert "\\"))
- (self-insert-command arg))
-
- (defun c++-electric-delete (arg)
- "If `c++-hungry-delete-key' is non-nil, consumes all preceding
- whitespace unless ARG is supplied, or point is inside a C or C++ style
- comment or string. If ARG is supplied, this just calls
- `backward-delete-char-untabify' passing along ARG.
-
- If `c++-hungry-delete-key' is nil, just call `backward-delete-char-untabify'."
- (interactive "P")
- (cond
- ((or (not c++-hungry-delete-key) arg)
- (funcall c++-delete-function (prefix-numeric-value arg)))
- ((let ((bod (c++-point 'bod)))
- (not (or (memq (c++-in-literal bod) '(c c++ string))
- (save-excursion
- (skip-chars-backward " \t")
- (= (preceding-char) ?#)))))
- (let ((here (point)))
- (skip-chars-backward " \t\n")
- (if (/= (point) here)
- (delete-region (point) here)
- (funcall c++-delete-function 1))))
- (t (funcall c++-delete-function 1))))
-
- (defun c++-electric-pound (arg)
- "Electric pound command."
- (interactive "p")
- (if (memq (c++-in-literal) '(c c++ string))
- (self-insert-command arg)
- (let ((here (point-marker))
- (bobp (bobp))
- (bolp (bolp)))
- (if (memq 'alignleft c++-electric-pound-behavior)
- (progn (beginning-of-line)
- (delete-horizontal-space)))
- (if bobp
- (insert (make-string arg last-command-char))
- (insert-before-markers (make-string arg last-command-char)))
- (if (not bolp)
- (goto-char here))
- (set-marker here nil))))
-
- (defun c++-electric-brace (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (let (insertpos
- (last-command-char last-command-char)
- (bod (c++-point 'bod)))
- (if (and (not arg)
- (save-excursion
- (skip-chars-forward " \t")
- (eolp))
- (or (save-excursion
- (skip-chars-backward " \t")
- (bolp))
- (let ((c++-auto-newline c++-auto-newline)
- (open-brace-p (= last-command-char ?{)))
- (if (and open-brace-p
- (or (eq c++-hanging-braces t)
- (and c++-hanging-braces
- (not (c++-at-top-level-p t bod)))))
- (setq c++-auto-newline nil))
- (if (c++-auto-newline)
- ;; this may have auto-filled so we need to
- ;; indent the previous line. we also need to
- ;; indent the currently line, or
- ;; c++-beginning-of-defun will not be able to
- ;; correctly find the bod when
- ;; c++-match-headers-strongly is nil.
- (progn (c++-indent-line)
- (save-excursion
- (forward-line -1)
- (c++-indent-line))))
- t)))
- (progn
- (if (and (memq last-command-char c++-untame-characters)
- (memq (c++-in-literal bod) '(c c++)))
- (insert "\\"))
- ;; we need to work around a bogus feature of Emacs where an
- ;; open brace at bolp means a beginning-of-defun. but it
- ;; really might not.
- (and (= last-command-char ?{)
- (bolp)
- (c++-indent-line))
- (insert last-command-char)
- ;; try to clean up empty defun braces if conditions apply
- (let ((here (point-marker)))
- (and (memq 'empty-defun-braces c++-cleanup-list)
- (c++-at-top-level-p t bod)
- c++-auto-newline
- (= last-command-char ?\})
- (progn (forward-char -1)
- (skip-chars-backward " \t\n")
- (= (preceding-char) ?\{))
- (not (memq (c++-in-literal) '(c c++ string)))
- (delete-region (point) (1- here)))
- (goto-char here)
- (set-marker here nil))
- (let ((here (point-marker))
- mbeg mend)
- (if (and (memq 'brace-else-brace c++-cleanup-list)
- (= last-command-char ?\{)
- (let ((status
- (re-search-backward "}[ \t\n]*else[ \t\n]*{"
- nil t)))
- (setq mbeg (match-beginning 0)
- mend (match-end 0))
- status)
- (= mend here)
- (not (memq (c++-in-literal bod) '(c c++ string))))
- (progn
- ;; we should clean up brace-else-brace syntax
- (delete-region mbeg mend)
- (insert-before-markers "} else {")
- (goto-char here)
- (set-marker here nil))
- (goto-char here)
- (set-marker here nil)))
- (c++-indent-line)
- (if (c++-auto-newline)
- (progn
- ;; c++-auto-newline may have done an auto-fill
- (save-excursion
- (let ((here (point-marker)))
- (goto-char (- (point) 2))
- (c++-indent-line)
- (setq insertpos (- (goto-char here) 2))
- (set-marker here nil)))
- (c++-indent-line)))
- (save-excursion
- (if insertpos (goto-char (1+ insertpos)))
- (delete-char -1))))
- (if insertpos
- (save-excursion
- (goto-char insertpos)
- (self-insert-command (prefix-numeric-value arg)))
- (self-insert-command (prefix-numeric-value arg)))))
-
- (defun c++-electric-slash (arg)
- "Insert slash, and if slash is second of a double-slash comment
- introducing construct, indent line as comment. This only indents if
- we're on a comment-only line, otherwise use `indent-for-comment' (\\[indent-for-comment])."
- (interactive "P")
- (let ((here (point)) char)
- (self-insert-command (prefix-numeric-value arg))
- (and (setq char (char-after (1- here)))
- (= char ?/)
- (save-excursion
- (goto-char here)
- (c++-indent-line)))))
-
- (defun c++-electric-star (arg)
- "Works with `c++-electric-slash' to auto indent C style comment lines."
- (interactive "P")
- (let ((here (point)) char)
- (self-insert-command (prefix-numeric-value arg))
- (if (and (setq char (char-after (1- here)))
- (memq (c++-in-literal) '(c))
- (memq char '(?/ ?* ?\t 32 ?\n))
- (save-excursion
- (skip-chars-backward "* \t")
- (if (= (preceding-char) ?/)
- (progn
- (forward-char -1)
- (skip-chars-backward " \t")))
- (bolp)))
- (save-excursion
- (goto-char here)
- (c++-indent-line)))))
-
- (defun c++-electric-semi (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (if (c++-in-literal)
- (self-insert-command (prefix-numeric-value arg))
- (let ((here (point-marker)))
- (if (and (memq 'defun-close-semi c++-cleanup-list)
- c++-auto-newline
- (progn
- (skip-chars-backward " \t\n")
- (= (preceding-char) ?})))
- (delete-region here (point)))
- (goto-char here)
- (set-marker here nil))
- (c++-electric-terminator arg)))
-
- (defun c++-electric-colon (arg)
- "Electrify colon.
- De-auto-newline double colons. No auto-new-lines for member
- initialization list."
- (interactive "P")
- (if (c++-in-literal)
- (self-insert-command (prefix-numeric-value arg))
- (let ((c++-auto-newline c++-auto-newline)
- (insertion-point (point))
- (bod (c++-point 'bod)))
- (save-excursion
- (cond
- ;; check for double-colon where the first colon is not in a
- ;; comment or literal region
- ((progn (skip-chars-backward " \t\n")
- (and (= (preceding-char) ?:)
- (not (memq (c++-in-literal bod) '(c c++ string)))))
- (progn (delete-region insertion-point (point))
- (setq c++-auto-newline nil
- insertion-point (point))))
- ;; check for ?: construct which may be at any level
- ((progn (goto-char insertion-point)
- (condition-case premature-end
- (backward-sexp 1)
- (error nil))
- ;; is possible that the sexp we just skipped was a
- ;; negative number. in that case the minus won't be
- ;; gobbled
- (skip-chars-backward "-")
- (c++-backward-syntactic-ws bod)
- (= (preceding-char) ?\?))
- (setq c++-auto-newline nil))
- ;; check for being at top level or top with respect to the
- ;; class. if not, process as normal
- ((progn (goto-char insertion-point)
- (not (c++-at-top-level-p t bod))))
- ;; if at top level, check to see if we are introducing a member
- ;; init list. if not, continue
- ((progn (c++-backward-syntactic-ws bod)
- (= (preceding-char) ?\)))
- (goto-char insertion-point)
- ;; at a member init list, figure out about auto newlining. if
- ;; nil or before then put a newline before the colon and
- ;; adjust the insertion point, but *only* if there is no
- ;; newline already before the insertion point
- (if (and (memq c++-hanging-member-init-colon '(nil before))
- c++-auto-newline)
- (if (not (save-excursion (skip-chars-backward " \t")
- (bolp)))
- (let ((c++-auto-newline t))
- (c++-auto-newline)
- (setq insertion-point (point)))))
- ;; if hanging colon is after or nil, then newline is inserted
- ;; after colon. set up variable so c++-electric-terminator
- ;; places the newline correctly
- (setq c++-auto-newline
- (and c++-auto-newline
- (memq c++-hanging-member-init-colon '(nil after)))))
- ;; last condition is always put newline after colon
- (t (setq c++-auto-newline nil))
- )) ; end-cond, end-save-excursion
- (goto-char insertion-point)
- (c++-electric-terminator arg))))
-
- (defun c++-electric-terminator (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (let (insertpos (end (point)))
- (if (and (not arg)
- (save-excursion
- (skip-chars-forward " \t")
- (eolp))
- (not (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (or (= (following-char) ?#)
- ;; Colon is special only after a label, or
- ;; case, or another colon.
- ;; 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 ":")))
- (progn
- (c++-beginning-of-defun)
- (let* ((parse-sexp-ignore-comments t)
- (pps (parse-partial-sexp (point) end)))
- (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))))
- (progn
- (insert last-command-char)
- (c++-indent-line)
- (and c++-auto-newline
- (not (c++-in-parens-p))
- (progn
- ;; the new marker object, used to be just an integer
- (setq insertpos (make-marker))
- ;; changed setq to set-marker
- (set-marker insertpos (1- (point)))
- ;; do this before the newline, since in auto fill can break
- (newline)
- (c++-indent-line)))
- (save-excursion
- (if insertpos (goto-char (1+ insertpos)))
- (delete-char -1))))
- (if insertpos
- (save-excursion
- (goto-char insertpos)
- (self-insert-command (prefix-numeric-value arg)))
- (self-insert-command (prefix-numeric-value arg)))))
-
- (defun c++-indent-command (&optional whole-exp)
- "Indent current line as C++ code, or in some cases insert a tab character.
-
- If `c++-tab-always-indent' is t, always just indent the current line.
- If nil, indent the current line only if point is at the left margin or
- in the line's indentation; otherwise insert a tab. If not-nil-or-t,
- then tab is inserted only within literals (comments and strings) and
- inside preprocessor directives, but line is always reindented.
-
- A numeric argument, regardless of its value, means indent rigidly all
- the lines of the expression starting after point so that this line
- becomes properly indented. The relative indentation among the lines
- of the expression are preserved."
- (interactive "P")
- (let ((bod (c++-point 'bod)))
- (if whole-exp
- ;; If arg, always indent this line as C
- ;; and shift remaining lines of expression the same amount.
- (let ((shift-amt (c++-indent-line bod))
- beg end)
- (save-excursion
- (if (eq c++-tab-always-indent t)
- (beginning-of-line))
- (setq beg (point))
- (forward-sexp 1)
- (setq end (point))
- (goto-char beg)
- (forward-line 1)
- (setq beg (point)))
- (if (> end beg)
- (indent-code-rigidly beg end shift-amt "#")))
- (cond
- ;; CASE 1: indent when at column zero or in lines indentation,
- ;; otherwise insert a tab
- ((not c++-tab-always-indent)
- (if (and (save-excursion
- (skip-chars-backward " \t")
- (bolp))
- (or (looking-at "[ \t]*$")
- (/= (point) (c++-point 'boi))
- (bolp)))
- (c++-indent-line bod)
- (insert-tab)))
- ;; CASE 2: just indent the line
- ((eq c++-tab-always-indent t)
- (c++-indent-line bod))
- ;; CASE 3: if in a literal, insert a tab, but always indent the line
- ((or (memq (c++-in-literal bod) '(c c++ string))
- (save-excursion
- (skip-chars-backward " \t")
- (= (preceding-char) ?#)))
- (let ((here (point))
- (boi (save-excursion (back-to-indentation) (point)))
- (indent-p nil))
- (c++-indent-line bod)
- (save-excursion
- (back-to-indentation)
- (setq indent-p (and (> here boi) (= (point) boi))))
- (if indent-p (insert-tab))))
- ;; CASE 4: bogus, just indent the line
- (t (c++-indent-line bod))))))
-
- (defun c++-indent-exp ()
- "Indent each line of the C++ grouping following point."
- (interactive)
- (let ((indent-stack (list nil))
- (contain-stack (list (point)))
- (case-fold-search nil)
- restart outer-loop-done inner-loop-done state ostate
- this-indent last-sexp last-depth
- at-else at-brace
- (parse-sexp-ignore-comments t)
- (opoint (point))
- (next-depth 0))
- (save-excursion
- (forward-sexp 1))
- (save-excursion
- (setq outer-loop-done nil)
- (while (and (not (eobp)) (not outer-loop-done))
- (setq last-depth next-depth)
- ;; Compute how depth changes over this line
- ;; plus enough other lines to get to one that
- ;; does not end inside a comment or string.
- ;; Meanwhile, do appropriate indentation on comment lines.
- (setq inner-loop-done nil)
- (while (and (not inner-loop-done)
- (not (and (eobp) (setq outer-loop-done t))))
- (setq ostate state)
- ;; fix by reed@adapt.net.com
- ;; must pass in the return past the end of line, so that
- ;; parse-partial-sexp finds it, and recognizes that a "//"
- ;; comment is over. otherwise, state is set that we're in a
- ;; comment, and never gets unset, causing outer-loop to only
- ;; terminate in (eobp). old:
- ;;(setq state (parse-partial-sexp (point)
- ;;(progn (end-of-line) (point))
- ;;nil nil state))
- (let ((start (point))
- (line-end
- (progn (end-of-line)
- (while (eq (c++-in-literal) 'c)
- (forward-line 1)
- (c++-indent-line)
- (end-of-line))
- (skip-chars-backward " \t")
- (end-of-line)
- (point)))
- (end (progn (if (not (eobp)) (forward-char)) (point))))
- (setq state (parse-partial-sexp start end nil nil state))
- (goto-char line-end))
- (setq next-depth (car state))
- (if (and (car (cdr (cdr state)))
- (>= (car (cdr (cdr state))) 0))
- (setq last-sexp (car (cdr (cdr state)))))
- (if (or (nth 4 ostate))
- (c++-indent-line))
- (if (or (nth 3 state))
- (forward-line 1)
- (setq inner-loop-done t)))
- (if (<= next-depth 0)
- (setq outer-loop-done t))
- (if outer-loop-done
- nil
- ;; If this line had ..))) (((.. in it, pop out of the levels
- ;; that ended anywhere in this line, even if the final depth
- ;; doesn't indicate that they ended.
- (while (> last-depth (nth 6 state))
- (setq indent-stack (cdr indent-stack)
- contain-stack (cdr contain-stack)
- last-depth (1- last-depth)))
- (if (/= last-depth next-depth)
- (setq last-sexp nil))
- ;; Add levels for any parens that were started in this line.
- (while (< last-depth next-depth)
- (setq indent-stack (cons nil indent-stack)
- contain-stack (cons nil contain-stack)
- last-depth (1+ last-depth)))
- (if (null (car contain-stack))
- (setcar contain-stack (or (car (cdr state))
- (save-excursion (forward-sexp -1)
- (point)))))
- (forward-line 1)
- (skip-chars-forward " \t")
- ;; check for C comment block
- (if (memq (c++-in-literal) '(c))
- (let ((eoc (save-excursion
- (re-search-forward "\\*/" (point-max) 'move)
- (point))))
- (while (< (point) eoc)
- (c++-indent-line)
- (forward-line 1))))
- (if (eolp)
- nil
- (if (and (car indent-stack)
- (>= (car indent-stack) 0))
- ;; Line is on an existing nesting level.
- ;; Lines inside parens are handled specially.
- (if (or (/= (char-after (car contain-stack)) ?{)
- ;;(c++-at-top-level-p t))
- ;; baw hack for continued statement offsets
- ;; repercussions???
- t)
- (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-syntactic-ws 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)
- (back-to-indentation)
- (skip-chars-forward "{ \t")
- (setq this-indent (current-column)))
- (setq this-indent (car indent-stack))))))
- ;; Just started a new nesting level.
- ;; Compute the standard indent for this level.
- (let ((val (c++-calculate-indent
- (if (car indent-stack)
- (- (car indent-stack))))))
- (setcar indent-stack
- (setq this-indent val))))
- ;; Adjust line indentation according to its contents
- (cond
- ;; looking at public, protected, private line
- ((looking-at c++-access-key)
- (setq this-indent (+ this-indent c++-access-specifier-offset)))
- ;; looking at a case, default, or other label
- ((or (looking-at "\\(case[ \t]+.*\\|default[ \t]*\\):")
- (and (looking-at "[A-Za-z]")
- (save-excursion
- (forward-sexp 1)
- (looking-at ":[^:]"))))
- (setq this-indent (max 0 (+ this-indent c-label-offset))))
- ;; looking at a comment only line?
- ((looking-at comment-start-skip)
- ;; different indentation base on whether this is a col0
- ;; comment only line or not. also, if comment is in, or
- ;; to the right of comment-column, the comment doesn't
- ;; move
- (progn
- (skip-chars-forward " \t")
- (setq this-indent
- (if (>= (current-column) comment-column)
- (current-column)
- (c++-comment-offset
- (bolp)
- (+ this-indent
- (if (save-excursion
- (c++-backward-syntactic-ws
- (car contain-stack))
- (memq (preceding-char)
- '(nil ?\, ?\; ?} ?: ?{)))
- 0 c-continued-statement-offset))
- )))))
- ;; looking at a friend declaration
- ((looking-at "friend[ \t]")
- (setq this-indent (+ this-indent c++-friend-offset)))
- ;; looking at a close brace
- ((= (following-char) ?})
- (setq this-indent (- this-indent c-indent-level)))
- ;; looking at an open brace
- ((= (following-char) ?{)
- (setq this-indent
- (+ this-indent c-brace-offset
- (if (c++-at-top-level-p t (car contain-stack))
- 0 c-indent-level))))
- ;; check for continued statements
- ((save-excursion
- (c++-backward-syntactic-ws (car contain-stack))
- (and (not (c++-in-parens-p))
- (not (memq (preceding-char) '(nil ?\000 ?\; ?\} ?\: ?\{)))
- (progn
- (beginning-of-line)
- (skip-chars-forward " \t")
- (not (looking-at c++-class-key)))))
- (setq this-indent
- (+ this-indent
- c-continued-statement-offset
- ;; are we in a member init list?
- (if (not (looking-at "[ \t]*:"))
- (save-excursion
- (let ((lim (car contain-stack)))
- (c++-backward-syntactic-ws lim)
- (while (and (< lim (point))
- (= (preceding-char) ?,))
- (beginning-of-line)
- (c++-backward-syntactic-ws))
- (forward-line 1)
- (beginning-of-line)
- (if (looking-at "[ \t]*:")
- (- (save-excursion
- (skip-chars-forward " \t")
- (point))
- (point))
- 0)))
- 0)
- )))
- ;; check for stream operator
- ((looking-at "\\(<<\\|>>\\)")
- (setq this-indent (c++-calculate-indent)))
- ) ;; end-cond
- ;; Put chosen indentation into effect.
- (or (= (current-column) this-indent)
- (= (following-char) ?\#)
- (progn
- (delete-region (point) (progn (beginning-of-line) (point)))
- (indent-to this-indent)))
- ;; Indent any comment following the text.
- (or (looking-at comment-start-skip)
- (if (re-search-forward
- comment-start-skip
- (c++-point 'eol) t)
- (progn (indent-for-comment)
- (beginning-of-line))))
- ))))))
-
- (defun c++-insert-header ()
- "Insert header denoting C++ code at top of buffer."
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (insert "// "
- "This may look like C code, but it is really "
- "-*- C++ -*-"
- "\n\n")))
-
- (defun c++-tame-comments ()
- "Backslashifies all untamed in comment regions found in the buffer.
- This is a workaround for Emacs syntax bugs. This function is
- unnecessary (and un-used automatically) if you are running a patched
- Emacs. Untamed characters to escape are defined in the variable
- `c++-untame-characters'."
- (interactive)
- ;; make the list into a valid charset, escaping where necessary
- (let ((charset (concat "^" (mapconcat
- (function
- (lambda (char)
- (if (memq char '(?\\ ?^ ?-))
- (concat "\\" (char-to-string char))
- (char-to-string char))))
- c++-untame-characters ""))))
- (save-excursion
- (beginning-of-buffer)
- (while (not (eobp))
- (skip-chars-forward charset)
- (if (and (not (zerop (following-char)))
- (memq (c++-in-literal) '(c c++))
- (/= (preceding-char) ?\\ ))
- (insert "\\"))
- (if (not (eobp))
- (forward-char 1))))))
-
- ;; taken from match-paren.el. Author: unknown
- (defun c++-match-paren ()
- "Jumps to the paren matching the one under point, if there is one."
- (interactive)
- (let ((parse-sexp-ignore-comments (memq 'v19 c++-emacs-features)))
- (cond
- ((looking-at "[\(\[{]")
- (forward-sexp 1)
- (backward-char))
- ((looking-at "[])}]")
- (forward-char)
- (backward-sexp 1))
- (t (message "Could not find matching paren.")))))
-
- (defun c++-forward-sexp (&optional arg)
- "Safe forward-sexp call."
- (interactive "p")
- (let ((parse-sexp-ignore-comments (memq 'v19 c++-emacs-features)))
- (forward-sexp arg)))
-
- (defun c++-backward-sexp (&optional arg)
- "Safe backward-sexp call."
- (interactive "p")
- (let ((parse-sexp-ignore-comments (memq 'v19 c++-emacs-features)))
- (backward-sexp arg)))
-
-
- ;; ======================================================================
- ;; compatibility between emacsen
- ;; ======================================================================
-
- ;; This is the best we can do in vanilla GNU 18 emacsen. Note that the
- ;; following problems exist:
- ;; 1. We only look back to LIM, and that could place us inside a
- ;; literal if we are scanning backwards over lots of comments
- ;; 2. This can potentially get slower the larger LIM is
- ;; If anybody has a better solution, I'll all ears
- (defun c++-backward-syntactic-ws (&optional lim)
- "Skip backwards over syntactic whitespace.
- Syntactic whitespace is defined as lexical whitespace, C and C++ style
- comments, and preprocessor directives. Search no farther back than
- optional LIM. If LIM is omitted, `beginning-of-defun' is used."
- (let ((lim (or lim (c++-point 'bod)))
- literal stop)
- (if (and c++-backscan-limit
- (> (- (point) lim) c++-backscan-limit))
- (setq lim (- (point) c++-backscan-limit)))
- (while (not stop)
- (skip-chars-backward " \t\n\r\f" lim)
- ;; c++ comment
- (if (eq (setq literal (c++-in-literal lim)) 'c++)
- (progn
- (skip-chars-backward "^/" lim)
- (skip-chars-backward "/" lim)
- (while (not (or (and (= (following-char) ?/)
- (= (char-after (1+ (point))) ?/))
- (<= (point) lim)))
- (skip-chars-backward "^/" lim)
- (skip-chars-backward "/" lim)))
- ;; c comment
- (if (eq literal 'c)
- (progn
- (skip-chars-backward "^*" lim)
- (skip-chars-backward "*" lim)
- (while (not (or (and (= (following-char) ?*)
- (= (preceding-char) ?/))
- (<= (point) lim)))
- (skip-chars-backward "^*" lim)
- (skip-chars-backward "*" lim))
- (or (bobp) (forward-char -1)))
- ;; preprocessor directive
- (if (eq literal 'pound)
- (progn
- (beginning-of-line)
- (setq stop (<= (point) lim)))
- ;; just outside of c block
- (if (and (= (preceding-char) ?/)
- (= (char-after (- (point) 2)) ?*))
- (progn
- (skip-chars-backward "^*" lim)
- (skip-chars-backward "*" lim)
- (while (not (or (and (= (following-char) ?*)
- (= (preceding-char) ?/))
- (<= (point) lim)))
- (skip-chars-backward "^*" lim)
- (skip-chars-backward "*" lim))
- (or (bobp) (forward-char -1)))
- ;; none of the above
- (setq stop t))))))))
-
- ;; This defun works well for Lemacs 19.4-7, which implemented a first
- ;; shot at doing this via a C built-in backward-syntactic-ws. This
- ;; has been obsoleted in future Lemacsen and in FSF19
- (defun c++-fast-backward-syntactic-ws-1 (&optional lim)
- "Skip backwards over syntactic whitespace.
- Syntactic whitespace is defined as lexical whitespace, C and C++ style
- comments, and preprocessor directives. Search no farther back than
- optional LIM. If LIM is omitted, `beginning-of-defun' is used."
- (save-restriction
- (let ((parse-sexp-ignore-comments t)
- donep boi char
- (lim (or lim (c++-point 'bod))))
- (if (< lim (point))
- (unwind-protect
- (progn
- (narrow-to-region lim (point))
- ;; cpp statements are comments for our purposes here
- (if (eq major-mode 'c++-mode)
- (modify-syntax-entry ?# "< b" c++-mode-syntax-table)
- (modify-syntax-entry ?\n "> b" c++-c-mode-syntax-table)
- (modify-syntax-entry ?# "< b" c++-c-mode-syntax-table))
- (while (not donep)
- ;; if you're not running a patched lemacs, the new byte
- ;; compiler will complain about this function. ignore that
- (backward-syntactic-ws)
- (if (not (looking-at "#\\|/\\*\\|//\\|\n"))
- (forward-char 1))
- (setq boi (c++-point 'boi)
- char (char-after boi))
- (if (and char (= char ?#))
- (progn (goto-char boi)
- (setq donep (<= (point) lim)))
- (setq donep t))
- ))
- ;; cpp statements are not comments anywhere else
- (if (eq major-mode 'c++-mode)
- (modify-syntax-entry ?# "." c++-mode-syntax-table)
- (modify-syntax-entry ?\n " " c++-c-mode-syntax-table)
- (modify-syntax-entry ?# "." c++-c-mode-syntax-table))))
- )))
-
- ;; This is the way it should be done for all post 19.7 Lemacsen and
- ;; for all FSF19 implementations
- (defun c++-fast-backward-syntactic-ws-2 (&optional lim)
- "Skip backwards over syntactic whitespace.
- Syntactic whitespace is defined as lexical whitespace, C and C++ style
- comments, and preprocessor directives. Search no farther back than
- optional LIM. If LIM is omitted, `beginning-of-defun' is used."
- (save-restriction
- (let* ((lim (or lim (c++-point 'bod)))
- (here lim))
- (if (< lim (point))
- (unwind-protect
- (progn
- (narrow-to-region lim (point))
- ;; cpp statements are comments for our purposes here
- (if (eq major-mode 'c++-mode)
- (modify-syntax-entry ?# "< b" c++-mode-syntax-table)
- (modify-syntax-entry ?\n "> b" c++-c-mode-syntax-table)
- (modify-syntax-entry ?# "< b" c++-c-mode-syntax-table))
- (while (/= here (point))
- (setq here (point))
- (forward-comment -1)))
- ;; cpp statements are not comments everywhere else
- (if (eq major-mode 'c++-mode)
- (modify-syntax-entry ?# "." c++-mode-syntax-table)
- (modify-syntax-entry ?\n " " c++-c-mode-syntax-table)
- (modify-syntax-entry ?# "." c++-c-mode-syntax-table))))
- )))
-
- ;; This is the slow and ugly way, but its the best we can do in
- ;; vanilla GNU18 emacsen
- (defun c++-in-literal (&optional lim)
- "Determine if point is in a C++ ``literal''.
- Return `c' if in a C-style comment, `c++' if in a C++ style comment,
- `string' if in a string literal, `pound' if on a preprocessor line, or
- nil if not in a comment at all. Optional LIM is used as the backward
- limit of the search. If omitted, or nil, `c++-beginning-of-defun' is
- used."
- (save-excursion
- (let* ((here (point))
- (state nil)
- (match nil)
- (backlim (or lim (c++-point 'bod))))
- (goto-char backlim)
- (while (< (point) here)
- (setq match
- (and (re-search-forward "\\(/[/*]\\)\\|[\"']\\|\\(^[ \t]*#\\)"
- here 'move)
- (buffer-substring (match-beginning 0) (match-end 0))))
- (setq state
- (cond
- ;; no match
- ((null match) nil)
- ;; looking at the opening of a C++ style comment
- ((string= "//" match)
- (if (<= here (progn (end-of-line) (point))) 'c++))
- ;; looking at the opening of a C block comment
- ((string= "/*" match)
- (if (not (re-search-forward "*/" here 'move)) 'c))
- ;; looking at the opening of a double quote string
- ((string= "\"" match)
- (if (not (save-restriction
- ;; this seems to be necessary since the
- ;; re-search-forward will not work without it
- (narrow-to-region (point) here)
- (re-search-forward
- ;; this regexp matches a double quote
- ;; which is preceded by an even number
- ;; of backslashes, including zero
- "\\([^\\]\\|^\\)\\(\\\\\\\\\\)*\"" here 'move)))
- 'string))
- ;; looking at the opening of a single quote string
- ((string= "'" match)
- (if (not (save-restriction
- ;; see comments from above
- (narrow-to-region (point) here)
- (re-search-forward
- ;; this matches a single quote which is
- ;; preceded by zero or two backslashes.
- "\\([^\\]\\|^\\)\\(\\\\\\\\\\)?'"
- here 'move)))
- 'string))
- ((string-match "[ \t]*#" match)
- (if (<= here (progn (end-of-line) (point))) 'pound))
- (t nil)))
- ) ; end-while
- state)))
-
- ;; This is for all 8-bit emacsen (Lucid 19, patched GNU18)
- (defun c++-in-literal-8-bit (&optional lim)
- "Determine if point is in a C++ ``literal''.
- Return `c' if in a C-style comment, `c++' if in a C++ style comment,
- `string' if in a string literal, `pound' if on a preprocessor line, or
- nil if not in a comment at all. Optional LIM is used as the backward
- limit of the search. If omitted, or nil, `c++-beginning-of-defun' is
- used."
- (save-excursion
- (let* ((backlim (or lim (c++-point 'bod)))
- (here (point))
- (parse-sexp-ignore-comments t) ; may not be necessary
- (state (parse-partial-sexp backlim (point))))
- (cond
- ((nth 3 state) 'string)
- ((nth 4 state) (if (nth 7 state) 'c++ 'c))
- ((progn
- (goto-char here)
- (beginning-of-line)
- (looking-at "[ \t]*#"))
- 'pound)
- (t nil)))))
-
- ;; This is for all 1-bit emacsen (FSF19)
- (defun c++-in-literal-1-bit (&optional lim)
- "Determine if point is in a C++ ``literal''.
- Return `c' if in a C-style comment, `c++' if in a C++ style comment,
- `string' if in a string literal, `pound' if on a preprocessor line, or
- nil if not in a comment at all. Optional LIM is used as the backward
- limit of the search. If omitted, or nil, `c++-beginning-of-defun' is
- used."
- (save-excursion
- (let* ((backlim (or lim (c++-point 'bod)))
- (here (point))
- (parse-sexp-ignore-comments t) ; may not be necessary
- (state (parse-partial-sexp backlim (point))))
- (cond
- ((nth 3 state) 'string)
- ((nth 4 state) (if (nth 7 state) 'c 'c++))
- ((progn
- (goto-char here)
- (beginning-of-line)
- (looking-at "[ \t]*#"))
- 'pound)
- (t nil)))))
-
- (cond
- ((memq 'old-v19 c++-emacs-features)
- (fset 'c++-backward-syntactic-ws 'c++-fast-backward-syntactic-ws-1))
- ((memq 'v19 c++-emacs-features)
- (fset 'c++-backward-syntactic-ws 'c++-fast-backward-syntactic-ws-2))
- )
- (cond
- ((memq '8-bit c++-emacs-features)
- (fset 'c++-in-literal 'c++-in-literal-8-bit))
- ((memq '1-bit c++-emacs-features)
- (fset 'c++-in-literal 'c++-in-literal-1-bit))
- )
-
-
- ;; ======================================================================
- ;; defuns for parsing syntactic elements
- ;; ======================================================================
- (defun c++-parse-state (&optional limit)
- "Determinate the syntactic state of the code at point.
- Iteratively uses `parse-partial-sexp' from point to LIMIT and returns
- the result of `parse-partial-sexp' at point. LIMIT is optional and
- defaults to `point-max'."
- (let ((limit (or limit (point-max)))
- (parse-sexp-ignore-comments t)
- state)
- (while (< (point) limit)
- (setq state (parse-partial-sexp (point) limit 0)))
- state))
-
- (defun c++-at-top-level-p (wrt &optional bod)
- "Return t if point is not inside a containing C++ expression, nil
- if it is embedded in an expression. When WRT is non-nil, returns nil
- if not at the top level with respect to an enclosing class, or the
- depth of class nesting at point. With WRT nil, returns nil if not at
- the ``real'' top level. Optional BOD is the beginning of defun."
- (save-excursion
- (let ((indent-point (point))
- (case-fold-search nil)
- state containing-sexp paren-depth
- (bod (or bod (c++-point 'bod)))
- foundp)
- (goto-char bod)
- (setq state (c++-parse-state indent-point)
- containing-sexp (nth 1 state)
- paren-depth (nth 0 state))
- (cond
- ((eq major-mode 'c++-c-mode)
- (and (null containing-sexp) 0))
- ((not wrt)
- (null containing-sexp))
- ((null containing-sexp) 0)
- ((c++-in-parens-p) nil)
- (t
- ;; calculate depth wrt containing (possibly nested) classes
- (goto-char containing-sexp)
- (while (and (setq foundp (re-search-backward
- (concat "[;}]\\|" c++-class-key)
- (point-min) t))
- (let ((bod (c++-point 'bod)))
- (or (c++-in-literal bod)
- (c++-in-parens-p bod)
- ;; see if class key is inside a template spec
- (and (looking-at c++-class-key)
- (progn (skip-chars-backward " \t\n")
- (memq (preceding-char) '(?, ?<))))))))
- (if (memq (following-char) '(?} ?\;))
- nil
- (setq state (c++-parse-state containing-sexp))
- (and foundp
- (not (nth 1 state))
- (nth 2 state)
- paren-depth))
- )))))
-
- (defun c++-in-parens-p (&optional lim)
- "Return t if inside a paren expression.
- Optional LIM is used as the backward limit of the search."
- (let ((lim (or lim (c++-point 'bod))))
- (condition-case var
- (save-excursion
- (save-restriction
- (narrow-to-region (point) lim)
- (goto-char (point-max))
- (= (char-after (or (scan-lists (point) -1 1)
- (point-min)))
- ?\()))
- (error nil)
- )))
-
- (defun c++-in-function-p (&optional containing)
- "Return t if inside a C++ function definition.
- Optional CONTAINING is position of containing s-exp open brace. If not
- supplied, point is used as search start."
- (save-excursion
- (let ((here (if (not containing)
- (point)
- (goto-char containing)
- (c++-backward-syntactic-ws)
- (point))))
- (if (and (= (preceding-char) ?t)
- (forward-word -1)
- (looking-at "\\<const\\>"))
- (c++-backward-syntactic-ws)
- (goto-char here))
- (= (preceding-char) ?\)))))
-
-
- ;; ======================================================================
- ;; defuns for calculating indentation
- ;; ======================================================================
- (defun c++-indent-line (&optional bod)
- "Indent current line as C++ code.
- Return the amount the indentation changed by. Optional BOD is the
- point of the beginning of the C++ definition."
- (let* ((bod (or bod (c++-point 'bod)))
- (indent (c++-calculate-indent nil bod))
- beg shift-amt
- close-paren top-close-paren
- (case-fold-search nil)
- (pos (- (point-max) (point))))
- ;; calculate block close paren offset
- (if (listp c++-block-close-brace-offset)
- (setq close-paren (car c++-block-close-brace-offset)
- top-close-paren (cdr c++-block-close-brace-offset))
- (setq close-paren c++-block-close-brace-offset
- top-close-paren c++-block-close-brace-offset))
- ;; now start cleanup
- (beginning-of-line)
- (setq beg (point))
- (cond
- ((eq indent nil)
- (setq indent (current-indentation)))
- ((eq indent t)
- (setq indent (c++-calculate-c-indent-within-comment)))
- ((looking-at "[ \t]*#")
- (setq indent 0))
- ((save-excursion
- (back-to-indentation)
- (looking-at "//\\|/\\*"))
- ;; we've found a comment-only line. we now must try to determine
- ;; if the line is a continuation from a comment on the previous
- ;; line. we check to see if the comment starts in or to the
- ;; right of comment-column and if so, we don't change its
- ;; indentation.
- (skip-chars-forward " \t")
- (if (>= (current-column) comment-column)
- (setq indent (current-column))
- (setq indent (c++-comment-offset (bolp) indent))))
- (t
- (skip-chars-forward " \t")
- (if (listp indent) (setq indent (car indent)))
- (cond
- ((looking-at c++-access-key)
- (setq indent (+ indent c++-access-specifier-offset)))
- ((looking-at "default[ \t]*:")
- (setq indent (+ indent c-label-offset)))
- ((or (looking-at "case[ \t]+.*:")
- (and (looking-at "[A-Za-z]")
- (save-excursion
- (forward-sexp 1)
- (looking-at ":[^:]"))))
- (setq indent (max 1 (+ indent c-label-offset))))
- ((and (looking-at "else\\b")
- (not (looking-at "else\\s_")))
- (setq indent (save-excursion
- (c++-backward-to-start-of-if)
- (back-to-indentation)
- (skip-chars-forward "{ \t")
- (current-column))))
- ((looking-at "\\<friend\\>")
- (setq indent (+ indent c++-friend-offset)))
- ((and (= (following-char) ?\))
- c++-paren-as-block-close-p)
- (setq indent (+ (- indent c-indent-level)
- (if (save-excursion
- (forward-char 1)
- (c++-at-top-level-p nil bod))
- top-close-paren
- close-paren))))
- ((= (following-char) ?})
- (setq indent (+ (- indent c-indent-level)
- (if (save-excursion
- (forward-char 1)
- (c++-at-top-level-p nil bod))
- top-close-paren
- close-paren))))
- ((= (following-char) ?{)
- (setq indent (+ indent c-brace-offset))))))
- (skip-chars-forward " \t")
- (setq shift-amt (- indent (current-column)))
- (if (zerop shift-amt)
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos)))
- (delete-region beg (point))
- (indent-to indent)
- ;; If initial point was within line's indentation,
- ;; position after the indentation. Else stay at same point in text.
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos))))
- ;; save-excursion is necessary because things break if the hook
- ;; changes point or mark
- (save-excursion
- (run-hooks 'c++-special-indent-hook))
- shift-amt))
-
- (defun c++-cont-indent (ipnt char lim)
- "Calculate the indentation for a continued statement.
- IPNT is the indentation point; CHAR is the character before the
- indentation point, excluding any intervening whitespace; LIM is the
- minimum point to search backwards to."
- (let ((charlist '(nil ?\000 ?\, ?\; ?\} ?\: ?\{))
- streamop-pos here)
- (goto-char ipnt)
- (c++-backward-syntactic-ws lim)
- (if (not (memq char charlist))
- ;; This line is continuation of preceding line's statement
- (progn
- (c-backward-to-start-of-continued-exp lim)
- ;; take care of << and >> while in streams
- (setq here (point))
- (if (save-excursion
- (and (progn (goto-char ipnt)
- (looking-at "[ \t]*\\(<<\\|>>\\)"))
- (progn (goto-char here)
- (skip-chars-forward "^><\n")
- (setq streamop-pos (current-column))
- (looking-at "\\(<<\\|>>\\)"))))
- streamop-pos
- (+ (current-column)
- ;; prevent repeated continued indentation
- (if (save-excursion
- (beginning-of-line 1)
- (c++-backward-syntactic-ws lim)
- (memq (preceding-char) charlist))
- c-continued-statement-offset
- ;; the following statements *do* indent even
- ;; for single statements (are there others?)
- (if (looking-at "\\(do\\|else\\|for\\|if\\|while\\)\\b")
- c-continued-statement-offset
- ;; else may be a continued statement inside
- ;; a simple for/else/while/if/do loop
- (beginning-of-line 1)
- (forward-char -1)
- (c++-backward-syntactic-ws lim)
- (c-backward-to-start-of-continued-exp lim)
- (if (looking-at "\\(do\\|else\\|for\\|if\\|while\\)\\b")
- c-continued-statement-offset
- 0)))
- (save-excursion
- (goto-char ipnt)
- (skip-chars-forward " \t")
- (cond
- ((= (following-char) ?\{)
- c-continued-brace-offset)
- ((and (= (following-char) ?\})
- (progn (forward-char 1)
- (c++-at-top-level-p nil lim)))
- (- c-continued-statement-offset))
- (t 0))))))
- nil)))
-
- (defun c++-calculate-indent (&optional parse-start bod)
- "Return appropriate indentation for current line as C++ code.
- In usual case returns an integer: the column to indent to.
- Returns nil if line starts inside a string, t if in a comment.
- Optional PARSE-START is the location to start parsing, and optional
- BOD is the beginning of the C++ definition."
- (save-excursion
- (beginning-of-line)
- (let ((indent-point (point))
- (case-fold-search nil)
- state do-indentation literal in-meminit-p
- containing-sexp streamop-pos char-before-ip
- (inclass-shift 0) inclass-depth inclass-unshift
- (bod (or bod (c++-point 'bod))))
- (if parse-start
- (goto-char parse-start)
- (goto-char bod))
- (setq parse-start (point)
- state (c++-parse-state indent-point)
- containing-sexp (nth 1 state))
- ;; it is possible that c++-defun-header-weak could not find the
- ;; beginning of the C++ definition. The following code attempts
- ;; to work around this. It is probably better to just use
- ;; c++-match-header-strongly, but there are performance questions
- (if (null state)
- (let* ((c++-match-header-strongly t)
- (bod (c++-point 'bod)))
- (goto-char bod)
- (setq state (c++-parse-state indent-point)
- containing-sexp (nth 1 state)
- parse-start (point))))
- (setq literal (c++-in-literal bod))
- ;; cache char before indent point
- (save-excursion
- (goto-char indent-point)
- (c++-backward-syntactic-ws bod)
- (setq char-before-ip (preceding-char)))
- (cond
- ;; CASE 1: in a string.
- ((memq literal '(string)) nil)
- ;; CASE 2: in a C or C++ style comment.
- ((memq literal '(c c++)) t)
- ;; CASE 3: Line is at top level. May be comment-only line,
- ;; data or function definition, or may be function argument
- ;; declaration or member initialization. Indent like the
- ;; previous top level line unless:
- ;;
- ;; 1. the previous line ends in a closeparen without
- ;; semicolon, in which case this line is the first
- ;; argument declaration or member initialization, or
- ;;
- ;; 2. the previous line ends with a closeparen
- ;; (closebrace), optional spaces, and a semicolon, in
- ;; which case this line follows a multiline function
- ;; declaration (class definition), or
- ;;
- ;; 3. the previous line begins with a colon, in which
- ;; case this is the second line of member inits. It is
- ;; assumed that arg decls and member inits are not mixed.
- ;;
- ((setq inclass-depth (c++-at-top-level-p t bod))
- (+
- ;; add an offset if we are inside a class defun body, i.e. we
- ;; are at the top level, but only wrt a containing class
- (let ((shift/level (+ c-indent-level c-brace-imaginary-offset)))
- (setq inclass-shift (* shift/level inclass-depth)
- inclass-unshift (* shift/level (max 0 (1- inclass-depth))))
- inclass-shift)
- (progn
- (goto-char indent-point)
- (skip-chars-forward " \t")
- (cond
- ;;
- ((or (= (following-char) ?{)
- (progn
- (c++-backward-syntactic-ws parse-start)
- (bobp)))
- 0)
- ;; first arg decl or member init
- ((c++-in-function-p)
- (goto-char indent-point)
- (skip-chars-forward " \t")
- (if (= (following-char) ?:)
- c++-member-init-indent
- c-argdecl-indent))
- ;;
- ((progn
- (if (= (preceding-char) ?\;)
- (progn
- (backward-char 1)
- (skip-chars-backward " \t")))
- ;; may be first line after a hanging member init colon.
- ;; check to be sure its not a scope operator meaning we
- ;; are inside a member def
- (or (= (preceding-char) ?:)
- (save-excursion
- (forward-line 1)
- (skip-chars-forward " \t")
- (or (eobp) (forward-char 1))
- (and (= (preceding-char) ?:)
- (/= (following-char) ?:)))
- (save-excursion
- (and (= (preceding-char) ?,)
- (let ((bol (c++-point 'bol)))
- (skip-chars-backward "^:" bol)
- (= (preceding-char) ?:))
- (not (c++-in-parens-p))
- (progn
- (forward-char -1)
- (skip-chars-backward " \t")
- (not (bolp)))
- ;; make sure its not a multiple inheritance
- ;; continuation line
- (progn
- (beginning-of-line)
- (not (looking-at c++-inher-key)))
- ))))
- ;; check to see if we're looking at a member init, or
- ;; access specifier
- (if (progn
- (beginning-of-line)
- (skip-chars-forward " \t")
- (looking-at c++-access-key))
- ;; access specifier. class defun opening brace may
- ;; not be in col zero, and derived classes could be
- ;; on a separate line than class intro
- (progn
- (goto-char (or containing-sexp bod))
- (beginning-of-line)
- (skip-chars-forward " \t")
- (if (looking-at
- ":[ \t]*\\<\\(public\\|protected\\|private\\)\\>")
- (forward-line -1))
- (- (current-indentation)
- ;; remove some nested inclass indentation
- inclass-unshift))
- ;; member init, so add offset. add additional offset if
- ;; looking at line with just a member init colon
- (+ c++-member-init-indent
- (if (looking-at ":[ \t]*$")
- (or c++-continued-member-init-offset 0) 0))))
- ((or (= (preceding-char) ?})
- (= (preceding-char) ?\))
- (save-excursion
- (beginning-of-line)
- (looking-at "[ \t]*\\<friend\\>")))
- ;; indentation of class defun opening brace may not be
- ;; zero
- (goto-char (or containing-sexp bod))
- (- (current-indentation)
- ;; remove some nested inclass indentation
- inclass-unshift))
- ;; cont arg decls or member inits. we might be inside a
- ;; K&R C arg decl
- ((save-excursion
- (while (and (< bod (point))
- (memq (preceding-char) '(?\, ?\;)))
- (beginning-of-line)
- (c++-backward-syntactic-ws bod))
- (and (eq major-mode 'c++-c-mode)
- (= (preceding-char) ?\))))
- (+ c-argdecl-indent
- (progn
- (goto-char indent-point)
- (c++-backward-syntactic-ws bod)
- (if (= (preceding-char) ?,)
- c-continued-statement-offset
- 0))))
- ((progn
- (beginning-of-line)
- (skip-chars-forward " \t")
- (or (memq (c++-in-literal bod) '(c c++))
- (looking-at "/[/*]")))
- 0)
- ;; are we looking at the first member init?
- ((and (= (following-char) ?:)
- (save-excursion
- (c++-backward-syntactic-ws bod)
- (= (preceding-char) ?\))))
- (if c++-continued-member-init-offset
- (+ (current-indentation)
- c++-continued-member-init-offset)
- (progn
- (forward-char 1)
- (skip-chars-forward " \t")
- (- (current-column)
- inclass-shift))))
- ;; else first check to see if its a multiple inheritance
- ;; continuation line, but not a K&R C arg decl
- ((and (not (eq major-mode 'c++-c-mode))
- (looking-at c++-inher-key))
- (if (= char-before-ip ?,)
- (progn (goto-char (match-end 0))
- (current-column))
- ;; nope, its probably a nested class
- 0))
- ;; we might be looking at the opening brace of a class
- ;; defun
- ((= (following-char) ?\{)
- ;; indentation of opening brace may not be zero
- (- (current-indentation)
- ;; remove some nested inclass indentation
- inclass-unshift))
- ((eolp)
- ;; looking at a blank line, indent next line to zero
- 0)
- ;; at beginning of buffer, if nothing else, indent to zero
- ((save-excursion
- (goto-char indent-point)
- (beginning-of-line)
- (bobp))
- 0)
- ;; this could be a compound statement, but make sure its
- ;; not a member init list
- ((save-excursion
- (goto-char indent-point)
- (c++-backward-syntactic-ws bod)
- (and (= (preceding-char) ?,)
- (save-excursion
- (while (and (< bod (point))
- (= (preceding-char) ?,))
- (beginning-of-line)
- (c++-backward-syntactic-ws bod))
- (forward-line 1)
- (not (setq in-meminit-p (looking-at "[ \t]*:"))))))
- c-continued-statement-offset)
- (t
- (if (c++-in-parens-p)
- ;; we are perhaps inside a member init call
- (while (and (c++-in-parens-p)
- (< bod (point)))
- (forward-line -1)
- (skip-chars-forward " \t")))
- ;; check to be sure that we're not on the first line of
- ;; the member init list
- (if (and (= (following-char) ?:)
- (save-excursion
- (c++-backward-syntactic-ws bod)
- (= (preceding-char) ?\))))
- (progn
- (forward-char 1)
- (skip-chars-forward " \t")))
- ;; skip to start of compound statement, but only if we're
- ;; not in a member initialization list
- (if (not in-meminit-p)
- (let ((ipnt (point)))
- (c++-backward-syntactic-ws bod)
- (while (and (= (preceding-char) ?,)
- (< bod (point)))
- (beginning-of-line)
- (skip-chars-forward " \t")
- (setq ipnt (point))
- (c++-backward-syntactic-ws bod))
- (goto-char ipnt)))
- ;; subtract inclass-shift since its already incorporated
- ;; by default in current-column
- (- (current-column) inclass-shift)
- )))))
- ;; CASE 4: line is expression, not statement. indent to just
- ;; after the surrounding open -- unless empty arg list, in
- ;; which case we do what c++-empty-arglist-indent says to do.
- ((/= (char-after containing-sexp) ?{)
- (if (and c++-empty-arglist-indent
- (or c++-always-arglist-indent-p
- (null (nth 2 state))
- ;; indicates empty arg list. Use a heuristic: if
- ;; the first non-whitespace following left paren
- ;; on same line is not a comment, is not an empty
- ;; arglist.
- (save-excursion
- (goto-char (1+ containing-sexp))
- (looking-at "[ \t]*[/\n]"))))
- (progn
- (goto-char containing-sexp)
- (beginning-of-line)
- (skip-chars-forward " \t")
- (goto-char (min (+ (point) c++-empty-arglist-indent)
- (1+ containing-sexp)))
- (current-column))
- ;; In C-mode, we would always indent to one after the
- ;; left paren. Here, though, we may have an
- ;; empty-arglist, so we'll indent to the min of that
- ;; and the beginning of the first argument.
- (goto-char (1+ containing-sexp))
- ;; we want to skip any whitespace b/w open paren and
- ;; first argument. this handles while (thing) style
- ;; and while( thing ) style
- (skip-chars-forward " \t")
- (current-column)))
- ;; CASE 5: Statement. Find previous non-comment character.
- (t
- (or (c++-cont-indent indent-point char-before-ip containing-sexp)
- ;; This line may start a new statement, or it could
- ;; represent the while closure of a do/while construct
- (if (save-excursion
- (and (progn (goto-char indent-point)
- (skip-chars-forward " \t\n")
- (looking-at "while\\b"))
- (progn
- (c++-backward-to-start-of-do containing-sexp)
- (looking-at "do\\b"))
- (setq do-indentation (current-column))))
- do-indentation
- ;; this could be a case statement. if so we want to
- ;; indent it like the first case statement after a switch
- (if (save-excursion
- (goto-char indent-point)
- (skip-chars-forward " \t\n")
- (looking-at "\\(case[ \t]+.*\\|default[ \t]*\\):"))
- (progn
- (goto-char containing-sexp)
- (back-to-indentation)
- (+ (current-column) c-indent-level))
- ;; else, this is the start of a new statement
- ;; Position following last unclosed open.
- (goto-char containing-sexp)
- ;; Is line first statement after an open-brace?
- (or
- (and c++-relative-offset-p
- ;; 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]+.*\\|default[ \t]*\\):"
- "\\|[a-zA-Z0-9_$]*:[^:]"
- "\\|friend[ \t]"
- c++-class-key
- "[ \t]")))
- ;; Skip over comments and labels
- ;; following openbrace.
- (cond
- ((= (following-char) ?\#)
- (forward-line 1))
- ((looking-at "/\\*")
- (search-forward "*/" nil 'move))
- ((looking-at
- (concat "//\\|friend[ \t]" c++-class-key
- "[ \t]"))
- (forward-line 1))
- ((looking-at "\\(case[ \t]+.*\\|default[ \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)
- (c++-compound-offset
- char-before-ip containing-sexp bod)))))
- ;; If no previous statement, indent it relative to
- ;; line brace is on. For open brace in column
- ;; zero, don't let statement start there too. If
- ;; c-indent-offset is zero, use c-brace-offset +
- ;; c-continued-statement-offset instead. For
- ;; open-braces not the first thing in a line, add
- ;; in c-brace-imaginary-offset.
- (+ (if (and (bolp) (zerop c-indent-level))
- (+ c-brace-offset c-continued-statement-offset)
- c-indent-level)
- ;; Move back over whitespace before the openbrace.
- ;; If openbrace is not first nonwhite thing on the line,
- ;; add the c-brace-imaginary-offset.
- (progn (skip-chars-backward " \t")
- (if (bolp) 0 c-brace-imaginary-offset))
- ;; If the openbrace is preceded by a parenthesized exp,
- ;; move to the beginning of that;
- ;; possibly a different line
- (progn
- (if (eq (preceding-char) ?\))
- (forward-sexp -1))
- ;; Get initial indentation of the line we are on.
- (current-indentation)))))))) ; end t outer cond
- ))))
-
- (defun c++-calculate-c-indent-within-comment ()
- "Return the indentation amount for line, assuming that
- the current line is to be regarded as part of a block comment."
- (let (end stars indent)
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (setq stars (if (looking-at "\\*\\*?")
- (- (match-end 0) (match-beginning 0))
- 0))
- (skip-chars-backward " \t\n")
- (setq end (point))
- (beginning-of-line)
- (skip-chars-forward " \t")
- (if (re-search-forward "/\\*[ \t]*" end t)
- (goto-char (+ (match-beginning 0)
- (cond
- (c++-C-block-comments-indent-p 0)
- ((= stars 1) 1)
- ((= stars 2) 0)
- (t (- (match-end 0) (match-beginning 0)))))))
- (current-column))))
-
- (defun c++-comment-offset (col0-line-p indent)
- "Calculates and returns the comment-only line offset.
- Offset is based on the value of `c++-comment-only-line-offset', the
- argument COL0-LINE-P, and the current indentation INDENT."
- (let ((offset 0))
- (if col0-line-p
- ;; col0 means we need to look at the second member of the var's
- ;; list value. if value is not a list, then zero is used
- (if (listp c++-comment-only-line-offset)
- ;; it is a list, so second element must be nil or a number
- (setq offset
- (+ indent
- (or (car (cdr c++-comment-only-line-offset))
- (car c++-comment-only-line-offset)))))
- ;; not in column zero so indentation is car or value of variable
- (setq offset
- (+ indent
- (if (listp c++-comment-only-line-offset)
- (car c++-comment-only-line-offset)
- c++-comment-only-line-offset))))
- offset))
-
- (defun c++-compound-offset (char-before-ip containing-sexp bod)
- "Calculates any addition offset due a comma separated compound statement.
- CHAR-BEFORE-IP is the character before the indentation point and
- CONTAINING-SEXP is the buffer position of the open brace or paren.
- BOD is the `beginning-of-defun' point."
- (cond
- ;; not a compound statement
- ((/= char-before-ip ?,) 0)
- ;; open brace could be at column zero == bod
- ((and (= containing-sexp bod)
- (or (let ((lim (progn
- (goto-char containing-sexp)
- (forward-line -1)
- (point))))
- (end-of-line)
- (c++-backward-syntactic-ws lim)
- (= (preceding-char) ?=))
- (progn
- (beginning-of-line)
- (looking-at "\\(^\\|[ \t]*\\)enum[ \t]"))
- ))
- 0)
- ;; check for inside an enum
- ((let ((parse-sexp-ignore-comments t)
- in-enum-p)
- (goto-char containing-sexp)
- (while (< bod (point))
- (c++-backward-syntactic-ws)
- (if (memq (preceding-char) '(?\) ?\" ?\; ?\}))
- (goto-char bod)
- (forward-sexp -1)
- (if (looking-at "\\(enum[ \t\n]\\|\\[.*\\]\\)")
- (progn (goto-char bod)
- (setq in-enum-p t)))))
- in-enum-p)
- 0)
- ;; assume we're not in a list of enums or static array elems
- (t c-continued-statement-offset)
- ))
-
-
-
- ;; ======================================================================
- ;; defuns to look backwards for things
- ;; ======================================================================
-
- (defun c++-backward-to-start-of-do (&optional limit)
- "Move to the start of the last ``unbalanced'' do."
- (let ((do-level 1)
- (case-fold-search nil)
- (limit (or limit (c++-point 'bod))))
- (while (not (zerop do-level))
- ;; we protect this call because trying to execute this when the
- ;; while is not associated with a do will throw an error
- (condition-case err
- (progn
- (backward-sexp 1)
- (cond
- ((memq (c++-in-literal limit) '(c c++)))
- ((looking-at "while\\b")
- (setq do-level (1+ do-level)))
- ((looking-at "do\\b")
- (setq do-level (1- do-level)))
- ((< (point) limit)
- (setq do-level 0)
- (goto-char limit))))
- (error
- (goto-char limit)
- (setq do-level 0))))))
-
- (defun c++-backward-to-start-of-if (&optional limit)
- "Move to the start of the last ``unbalanced'' if."
- (let ((if-level 1)
- (case-fold-search nil)
- (limit (or limit (c++-point 'bod))))
- (while (and (not (bobp))
- (not (zerop if-level)))
- (c++-backward-syntactic-ws)
- (c++-backward-sexp 1)
- (cond ((looking-at "else\\b")
- (setq if-level (1+ if-level)))
- ((looking-at "if\\b")
- (setq if-level (1- if-level)))
- ((< (point) limit)
- (setq if-level 0)
- (goto-char limit))))))
-
- (defun c++-auto-newline ()
- "Insert a newline iff we're not in a literal.
- Literals are defined as being inside a C or C++ style comment or open
- string according to mode's syntax."
- (let ((bod (c++-point 'bod)))
- (and c++-auto-newline
- (not (c++-in-literal bod))
- (not (newline)))))
-
- (defun c++-point (position)
- "Returns the value of point at certain commonly referenced POSITIONs.
- POSITION can be one of the following symbols:
- `bol' -- beginning of line
- `eol' -- end of line
- `bod' -- beginning of defun
- `boi' -- back to indentation
- This function does not modify point or mark."
- (let ((here (point)) bufpos)
- (cond
- ((eq position 'bol) (beginning-of-line))
- ((eq position 'eol) (end-of-line))
- ((eq position 'bod) (c++-beginning-of-defun))
- ((eq position 'boi) (back-to-indentation))
- )
- (setq bufpos (point))
- (goto-char here)
- bufpos))
-
-
- ;; ======================================================================
- ;; defuns for "macroizations" -- making C++ parameterized types via macros
- ;; ======================================================================
- (defun c++-macroize-region (from to arg)
- "Insert backslashes at end of every line in region.
- Useful for defining cpp macros. If called with a prefix argument,
- it will remove trailing backslashes."
- (interactive "r\nP")
- (save-excursion
- (goto-char from)
- (beginning-of-line 1)
- (let ((line (count-lines (point-min) (point)))
- (to-line (save-excursion (goto-char to)
- (count-lines (point-min) (point)))))
- (while (< line to-line)
- (c++-backslashify-current-line (null arg))
- (forward-line 1) (setq line (1+ line))))))
-
- (defun c++-backslashify-current-line (doit)
- "Backslashifies current line."
- (end-of-line 1)
- (cond
- (doit
- ;; Note that "\\\\" is needed to get one backslash.
- (if (not (save-excursion (forward-char -1) (looking-at "\\\\")))
- (progn
- (if (>= (current-column) c++-default-macroize-column)
- (insert " \\")
- (while (<= (current-column) c++-default-macroize-column)
- (insert "\t") (end-of-line))
- (delete-char -1)
- (while (< (current-column) c++-default-macroize-column)
- (insert " ") (end-of-line))
- (insert "\\")))))
- (t
- (forward-char -1)
- (if (looking-at "\\\\")
- (progn (skip-chars-backward " \t")
- (kill-line))))))
-
-
- ;; ======================================================================
- ;; defuns for commenting out multiple lines.
- ;; ======================================================================
- (defun c++-comment-region (beg end)
- "Comment out all lines in a region between mark and current point by
- inserting `comment-start' in front of each line."
- (interactive "*r")
- (save-excursion
- (save-restriction
- (narrow-to-region
- (progn (goto-char beg) (beginning-of-line) (point))
- (progn (goto-char end) (or (bolp) (forward-line 1)) (point)))
- (goto-char (point-min))
- (while (not (eobp))
- (insert comment-start)
- (forward-line 1))
- (if (eq major-mode 'c++-c-mode)
- (insert comment-end)))))
-
- (defun c++-uncomment-region (beg end)
- "Uncomment all lines in region between mark and current point by deleting
- the leading ``// '' from each line, if any."
- (interactive "*r")
- (save-excursion
- (save-restriction
- (narrow-to-region
- (progn (goto-char beg) (beginning-of-line) (point))
- (progn (goto-char end) (forward-line 1) (point)))
- (goto-char (point-min))
- (let ((comment-regexp
- (if (eq major-mode 'c++-c-mode)
- (concat "\\s *\\(" (regexp-quote comment-start)
- "\\|" (regexp-quote comment-end)
- "\\)")
- (concat "\\s *" (regexp-quote comment-start)))))
- (while (not (eobp))
- (if (looking-at comment-regexp)
- (delete-region (match-beginning 0) (match-end 0)))
- (forward-line 1))))))
-
-
- ;; ======================================================================
- ;; grammar parsing
- ;; ======================================================================
-
- ;;; Below are two regular expressions that attempt to match defuns
- ;;; "strongly" and "weakly." The strong one almost reconstructs the
- ;;; grammar of C++; the weak one just figures anything id or curly on
- ;;; the left begins a defun. The constant "c++-match-header-strongly"
- ;;; determines which to use; the default is the weak one.
-
- (defvar c++-match-header-strongly nil
- "*If nil, use `c++-defun-header-weak' to identify beginning of definitions,
- if non-nil, use `c++-defun-header-strong'.")
-
- (defvar c++-defun-header-strong-struct-equivs
- "\\(class\\|struct\\|union\\|enum\\)"
- "Regexp to match names of structure declaration blocks in C++")
-
- (defconst c++-defun-header-strong
- (let*
- (; valid identifiers
- ;; There's a real weirdness here -- if I switch the below
- (id "\\(\\w\\|_\\)+")
- ;; to be
- ;; (id "\\(_\\|\\w\\)+")
- ;; things no longer work right. Try it and see!
-
- ; overloadable operators
- (op-sym1
- "[---+*/%^&|~!=<>]\\|[---+*/%^&|<>=!]=\\|<<=?\\|>>=?")
- (op-sym2
- "&&\\|||\\|\\+\\+\\|--\\|()\\|\\[\\]")
- (op-sym (concat "\\(" op-sym1 "\\|" op-sym2 "\\)"))
- ; whitespace
- (middle "[^\\*]*\\(\\*+[^/\\*][^\\*]*\\)*")
- (c-comment (concat "/\\*" middle "\\*+/"))
- (wh (concat "\\(\\s \\|\n\\|//.*$\\|" c-comment "\\)"))
- (wh-opt (concat wh "*"))
- (wh-nec (concat wh "+"))
- (oper (concat "\\(" "operator" "\\("
- wh-opt op-sym "\\|" wh-nec id "\\)" "\\)"))
- (dcl-list "([^():]*)")
- (func-name (concat "\\(" oper "\\|" id "::" id "\\|" id "\\)"))
- (inits
- (concat "\\(:"
- "\\(" wh-opt id "(.*\\()" wh-opt "," "\\)\\)*"
- wh-opt id "(.*)" wh-opt "{"
- "\\|" wh-opt "{\\)"))
- (type-name (concat
- "\\(" c++-defun-header-strong-struct-equivs wh-nec "\\)?"
- id))
- (type (concat "\\(const" wh-nec "\\)?"
- "\\(" type-name "\\|" type-name wh-opt "\\*+" "\\|"
- type-name wh-opt "&" "\\)"))
- (modifier "\\(inline\\|virtual\\|overload\\|auto\\|static\\)")
- (modifiers (concat "\\(" modifier wh-nec "\\)*"))
- (func-header
- ;; type arg-dcl
- (concat modifiers type wh-nec func-name wh-opt dcl-list wh-opt inits))
- (inherit (concat "\\(:" wh-opt "\\(public\\|protected\\|private\\)?"
- wh-nec id "\\)"))
- (cs-header (concat
- c++-defun-header-strong-struct-equivs
- wh-nec id wh-opt inherit "?" wh-opt "{")))
- (concat "^\\(" func-header "\\|" cs-header "\\)"))
- "Strongly-defined regexp to match beginning of structure or
- function definition.")
-
-
- ;; This part has to do with recognizing defuns.
-
- ;; The weak convention we will use is that a defun begins any time
- ;; there is a left curly brace, or some identifier on the left margin,
- ;; followed by a left curly somewhere on the line. (This will also
- ;; incorrectly match some continued strings, but this is after all
- ;; just a weak heuristic.) Suggestions for improvement (short of the
- ;; strong scheme shown above) are welcomed.
-
- (defconst c++-defun-header-weak "^{\\|^[_a-zA-Z].*{"
- "Weakly-defined regexp to match beginning of structure or function
- definition.")
-
-
- (defun c++-beginning-of-defun (&optional arg)
- "Find the beginning of the C++ function or class."
- (interactive "p")
- (if (not arg) (setq arg 1))
- (let ((c++-defun-header (if c++-match-header-strongly
- c++-defun-header-strong
- c++-defun-header-weak)))
- (cond
- ((or (= arg 0) (and (> arg 0) (bobp))) nil)
- ((and (not (looking-at c++-defun-header))
- (let ((curr-pos (point))
- (open-pos (if (search-forward "{" nil 'move)
- (point)))
- (beg-pos
- (if (re-search-backward c++-defun-header nil 'move)
- (match-beginning 0))))
- (if (and open-pos beg-pos
- (< beg-pos curr-pos)
- (> open-pos curr-pos))
- (progn
- (goto-char beg-pos)
- (if (= arg 1) t nil));; Are we done?
- (goto-char curr-pos)
- nil))))
- (t
- (if (and (looking-at c++-defun-header) (not (bobp)))
- (forward-char (if (< arg 0) 1 -1)))
- (and (re-search-backward c++-defun-header nil 'move (or arg 1))
- (goto-char (match-beginning 0)))))))
-
-
- (defun c++-end-of-defun (arg)
- "Find the end of the C++ function or class."
- (interactive "p")
- (let ((c++-defun-header (if c++-match-header-strongly
- c++-defun-header-strong
- c++-defun-header-weak))
- (parse-sexp-ignore-comments t))
- (if (and (eobp) (> arg 0))
- nil
- (if (and (> arg 0) (looking-at c++-defun-header)) (forward-char 1))
- (let ((pos (point)))
- (c++-beginning-of-defun
- (if (< arg 0)
- (- (- arg (if (eobp) 0 1)))
- arg))
- (if (and (< arg 0) (bobp))
- t
- (if (re-search-forward c++-defun-header nil 'move)
- (progn (forward-char -1)
- (forward-sexp)
- (beginning-of-line 2)))
- (if (and (= pos (point))
- (re-search-forward c++-defun-header nil 'move))
- (c++-end-of-defun 1))))
- t)))
-
- (defun c++-indent-defun ()
- "Indents the current function def, struct or class declaration."
- (interactive)
- (let ((restore (point)))
- (c++-end-of-defun 1)
- (beginning-of-line 1)
- (let ((end (point-marker)))
- (c++-beginning-of-defun)
- (while (and (< (point) end))
- (c++-indent-line)
- (forward-line 1)
- (beginning-of-line 1))
- (set-marker end nil))
- (goto-char restore)))
-
-
- ;; ======================================================================
- ;; defuns for submitting bug reports
- ;; ======================================================================
- (defconst c++-version "2.353"
- "c++-mode version number.")
- (defconst c++-mode-help-address "c++-mode-help@anthem.nlm.nih.gov"
- "Address accepting submission of bug reports.")
-
- (defun c++-version ()
- "Echo the current version of c++-mode."
- (interactive)
- (message "Using c++-mode.el %s" c++-version))
-
- (defun c++-submit-bug-report ()
- "Submit via mail a bug report on c++-mode."
- (interactive)
- (require 'reporter)
- (and
- (y-or-n-p "Do you want to submit a report on c++-mode? ")
- (reporter-submit-bug-report
- c++-mode-help-address
- (concat "c++-mode.el " c++-version " (editing "
- (if (eq major-mode 'c++-mode) "C++" "C")
- " code)")
- (list
- 'c++-emacs-features
- 'c++-C-block-comments-indent-p
- 'c++-access-specifier-offset
- 'c++-always-arglist-indent-p
- 'c++-auto-hungry-initial-state
- 'c++-auto-hungry-toggle
- 'c++-auto-newline
- 'c++-backscan-limit
- 'c++-block-close-brace-offset
- 'c++-cleanup-list
- 'c++-comment-only-line-offset
- 'c++-continued-member-init-offset
- 'c++-default-macroize-column
- 'c++-defun-header-strong-struct-equivs
- 'c++-delete-function
- 'c++-electric-pound-behavior
- 'c++-empty-arglist-indent
- 'c++-friend-offset
- 'c++-hanging-braces
- 'c++-hanging-member-init-colon
- 'c++-hungry-delete-key
- 'c++-match-header-strongly
- 'c++-member-init-indent
- 'c++-paren-as-block-close-p
- 'c++-relative-offset-p
- 'c++-tab-always-indent
- 'c++-untame-characters
- 'c-argdecl-indent
- 'c-brace-imaginary-offset
- 'c-brace-offset
- 'c-continued-brace-offset
- 'c-continued-statement-offset
- 'c-indent-level
- 'c-label-offset
- 'tab-width
- )
- (function
- (lambda ()
- (insert
- (if c++-special-indent-hook
- (concat "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
- "c++-special-indent-hook is set to '"
- (format "%s" c++-special-indent-hook)
- ".\nPerhaps this is your problem?\n"
- "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n")
- "\n")
- )))
- )))
-
-
- ;; this is sometimes useful
- (provide 'c++-mode)
-
- ;;; c++-mode.el ends here
-