(defgroup old-c++ nil
"Old C++ code editing mode for Emacs."
:prefix "c-")
(defvar c++-mode-abbrev-table nil
"Abbrev table used in C++ mode.")
(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 "{" 'electric-c++-brace)
(define-key c++-mode-map "}" 'electric-c++-brace)
(define-key c++-mode-map ";" 'electric-c++-semi)
(define-key c++-mode-map "\e\C-h" 'mark-c-function)
(define-key c++-mode-map "\e\C-q" 'indent-c++-exp)
(define-key c++-mode-map "\177" 'backward-delete-char-untabify)
(define-key c++-mode-map "\t" 'c++-indent-command)
(define-key c++-mode-map "\C-c\C-\\" 'c-backslash-region))
(defvar c++-mode-syntax-table nil
"Syntax table used in C++ mode.")
(if c++-mode-syntax-table
()
(setq c++-mode-syntax-table (make-syntax-table))
(modify-syntax-entry ?\\ "\\" c++-mode-syntax-table)
(modify-syntax-entry ?/ ". 14" c++-mode-syntax-table)
(modify-syntax-entry ?* ". 23" c++-mode-syntax-table)
(modify-syntax-entry ?+ "." c++-mode-syntax-table)
(modify-syntax-entry ?- "." c++-mode-syntax-table)
(modify-syntax-entry ?= "." c++-mode-syntax-table)
(modify-syntax-entry ?% "." c++-mode-syntax-table)
(modify-syntax-entry ?< "." c++-mode-syntax-table)
(modify-syntax-entry ?> "." c++-mode-syntax-table)
(modify-syntax-entry ?& "." c++-mode-syntax-table)
(modify-syntax-entry ?| "." c++-mode-syntax-table)
(modify-syntax-entry ?\' "\"" c++-mode-syntax-table)
(modify-syntax-entry ?* ". 23b" c++-mode-syntax-table)
(modify-syntax-entry ?/ ". 124" c++-mode-syntax-table)
(modify-syntax-entry ?\n ">" c++-mode-syntax-table)
(modify-syntax-entry ?\^m ">" c++-mode-syntax-table))
(defcustom 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."
:type '(choice (const nil) integer)
:group 'old-c++)
(defcustom c++-member-init-indent 0
"*Indentation level of member initializations in function declarations."
:type 'integer
:group 'old-c++)
(defcustom c++-friend-offset -4
"*Offset of C++ friend declarations relative to member declarations."
:type 'integer
:group 'old-c++)
(defcustom c++-electric-colon t
"*If t, colon is an electric terminator."
:type 'boolean
:group 'old-c++)
(defcustom c++-empty-arglist-indent nil
"*Indicates how far to indent an line following an empty argument
list. Nil indicates to just after the paren."
:type '(choice (const nil) integer)
:group 'old-c++)
(defvar c++-imenu-generic-expression
(`
((nil
(,
(concat
"^" "\\(template[ \t]*<[^>]+>[ \t]*\\)?" "\\([a-zA-Z0-9_:]+[ \t]+\\)?" "\\([a-zA-Z0-9_:]+[ \t]+\\)?"
"\\(" "[a-zA-Z0-9_:]+"
"\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)" "\\)?" "\\(" "[a-zA-Z0-9_:~]+" "\\|"
"\\([a-zA-Z0-9_:~]*::\\)?operator"
"[^a-zA-Z1-9_][^(]*" " \\)"
"[ \t]*([^)]*)[ \t\n]*[^ ;]"
)) 6)
("Class"
(, (concat
"^" "\\(template[ \t]*<[^>]+>[ \t]*\\)?" "class[ \t]+"
"\\([a-zA-Z0-9_]+\\)" "[ \t]*[:{]"
)) 2)
))
"Imenu generic expression for C++ mode. See `imenu-generic-expression'.")
(defun c++-mode ()
"Major mode for editing C++ code. Very much like editing C code.
Expression and list commands understand all C++ brackets.
Tab at left margin indents for C++ code
Comments are delimited with /* ... */ {or with // ... <newline>}
Paragraphs are separated by blank lines only.
Delete converts tabs to spaces as it moves back.
\\{c++-mode-map}
Variables controlling indentation style:
c-tab-always-indent
Non-nil means TAB in C mode should always reindent the current line,
regardless of where in the line point is when the TAB command is used.
Default is t.
c-auto-newline
Non-nil means automatically newline before and after braces,
and after colons and semicolons, inserted in C code.
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-continued-statement-offset
Extra indentation given to a substatement, such as the
then-clause of an if or body of a while.
c-continued-brace-offset
Extra indentation given to a brace that starts a substatement.
This is in addition to c-continued-statement-offset.
c-brace-offset
Extra indentation for line if it starts with an open brace.
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-argdecl-indent
Indentation level of declarations of C function arguments.
c-label-offset
Extra indentation for line that is a label, or case or ``default:'', or
``public:'' or ``private:'', or ``protected:''.
c++-electric-colon
If non-nil at invocation of c++-mode (t is the default) colon electrically
indents.
c++-empty-arglist-indent
If non-nil, a function declaration or invocation which ends a line with a
left paren is indented this many extra spaces, instead of flush with the
left paren.
c++-friend-offset
Offset of C++ friend declarations relative to member declarations.
c++-member-init-indent
Indentation level of member initializations in function declarations,
if they are on a separate line beginning with a colon.
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.
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++-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)
(require 'c-mode)
(use-local-map c++-mode-map)
(set-syntax-table c++-mode-syntax-table)
(setq major-mode 'c++-mode
mode-name "C++"
comment-column 32
local-abbrev-table c++-mode-abbrev-table)
(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-start-skip) "/\\*+ *\\|// *")
(set (make-local-variable 'comment-indent-function) 'c++-comment-indent)
(set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter))
(set (make-local-variable 'paragraph-separate) paragraph-start)
(set (make-local-variable 'paragraph-ignore-fill-prefix) t)
(set (make-local-variable 'require-final-newline) t)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(make-local-variable 'imenu-generic-expression)
(setq imenu-generic-expression c++-imenu-generic-expression)
(setq imenu-case-fold-search nil)
(run-hooks 'c++-mode-hook)
(if c++-electric-colon
(define-key c++-mode-map ":" 'electric-c++-terminator)))
(defun c++-comment-indent ()
(if (looking-at "^\\(/\\*\\|//\\)")
0 (save-excursion
(skip-chars-backward " \t")
(max
(if (zerop (current-column)) 0 (1+ (current-column)))
(let ((cur-pt (point)))
(beginning-of-line 0)
(if (re-search-forward comment-start-skip cur-pt t)
(progn
(goto-char (match-beginning 0))
(current-column))
comment-column))))))
(defun electric-c++-brace (arg)
"Insert character and correct line's indentation."
(interactive "P")
(let (insertpos)
(if (and (not arg)
(eolp)
(or (save-excursion
(skip-chars-backward " \t")
(bolp))
(if c-auto-newline (progn (c++-indent-line) (newline) t))))
(progn
(insert last-command-char)
(c++-indent-line)
(if c-auto-newline
(progn
(newline)
(setq insertpos (- (point) 2))
(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 electric-c++-semi (arg)
"Insert character and correct line's indentation."
(interactive "P")
(if c-auto-newline
(electric-c++-terminator arg)
(self-insert-command (prefix-numeric-value arg))))
(defun electric-c++-terminator (arg)
"Insert character and correct line's indentation."
(interactive "P")
(let (insertpos (end (point)))
(if (and (not arg) (eolp)
(not (save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(or (= (following-char) ?#)
(and (eq last-command-char ?:)
(or (not (or (looking-at "case[ \t]")
(save-excursion
(forward-word 1)
(skip-chars-forward " \t")
(>= (point) end))))
(save-excursion
(end-of-line 1)
(looking-at ":"))))
(progn
(beginning-of-defun)
(let ((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-inside-parens-p))
(progn
(setq insertpos (make-marker))
(set-marker insertpos (1- (point)))
(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 non-nil (the default), always indent current
line. Otherwise, indent the current line only if point is at the left
margin or in the line's indentation; otherwise insert a tab.
A numeric argument, regardless of its value, means indent rigidly all 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")
(if whole-exp
(let ((shift-amt (c++-indent-line))
beg end)
(save-excursion
(if c-tab-always-indent
(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 "#")))
(if (and (not c-tab-always-indent)
(save-excursion
(skip-chars-backward " \t")
(not (bolp))))
(insert-tab)
(c++-indent-line))))
(defun c++-indent-line ()
"Indent current line as C++ code.
Return the amount the indentation changed by."
(let ((indent (calculate-c++-indent nil))
beg shift-amt
(case-fold-search nil)
(pos (- (point-max) (point))))
(beginning-of-line)
(setq beg (point))
(cond ((eq indent nil)
(setq indent (current-indentation)))
((eq indent t)
(setq indent (calculate-c-indent-within-comment)))
((looking-at "[ \t]*#")
(setq indent 0))
(t
(skip-chars-forward " \t")
(if (listp indent) (setq indent (car indent)))
(cond ((looking-at "\\(default\\|public\\|private\\|protected\\):")
(setq indent (+ indent c-label-offset)))
((or (looking-at "case\\b")
(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)
(current-indentation))))
((looking-at "friend\[ \t]")
(setq indent (+ indent c++-friend-offset)))
((= (following-char) ?})
(setq indent (- indent c-indent-level)))
((= (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 (> (- (point-max) pos) (point))
(goto-char (- (point-max) pos))))
shift-amt))
(defun calculate-c++-indent (&optional parse-start)
"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."
(save-excursion
(beginning-of-line)
(let ((indent-point (point))
(case-fold-search nil)
state
containing-sexp)
(if parse-start
(goto-char parse-start)
(beginning-of-defun))
(while (< (point) indent-point)
(setq parse-start (point))
(setq state (parse-partial-sexp (point) indent-point 0))
(setq containing-sexp (car (cdr state))))
(cond ((or (nth 3 state) (nth 4 state))
(nth 4 state))
((null containing-sexp)
(goto-char indent-point)
(skip-chars-forward " \t")
(if (= (following-char) ?{)
0 (c++-backward-to-noncomment (or parse-start (point-min)))
(if (= (preceding-char) ?\))
(progn (goto-char indent-point)
(skip-chars-forward " \t")
(if (= (following-char) ?:)
c++-member-init-indent
c-argdecl-indent))
(if (= (preceding-char) ?\ (backward-char 1))
(if (= (preceding-char) ?})
0
(if (= (preceding-char) ?\))
(forward-list -1))
(beginning-of-line) (skip-chars-forward " \t")
(if (= (following-char) ?:)
(if c++-continued-member-init-offset
(+ (current-indentation)
c++-continued-member-init-offset)
(progn
(forward-char 1)
(skip-chars-forward " \t")
(current-column)))
(current-indentation)))
)))
((/= (char-after containing-sexp) ?{)
(if (and c++-empty-arglist-indent
(or (null (nth 2 state)) (save-excursion
(goto-char (1+ containing-sexp))
(not
(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))
(goto-char (1+ containing-sexp))
(current-column)))
(t
(goto-char indent-point)
(c++-backward-to-noncomment containing-sexp)
(if (and (not (memq (preceding-char) '(0 ?\, ?\ (save-excursion
(goto-char indent-point)
(skip-chars-forward " \t")
(not (= (following-char) ?}))))
(progn
(c-backward-to-start-of-continued-exp containing-sexp)
(+ c-continued-statement-offset (current-column)
(if (save-excursion (goto-char indent-point)
(skip-chars-forward " \t")
(eq (following-char) ?{))
c-continued-brace-offset 0)))
(goto-char containing-sexp)
(or
(save-excursion
(forward-char 1)
(let ((colon-line-end 0))
(while (progn (skip-chars-forward " \t\n")
(looking-at
(concat
"#\\|/\\*\\|//"
"\\|case[ \t]"
"\\|[a-zA-Z0-9_$]*:[^:]"
"\\|friend[ \t]")))
(cond ((= (following-char) ?\#)
(forward-line 1))
((looking-at "/\\*")
(search-forward "*/" nil 'move))
((looking-at "//\\|friend[ \t]")
(forward-line 1))
(t
(save-excursion (end-of-line)
(setq colon-line-end (point)))
(search-forward ":"))))
(and (< (point) indent-point)
(-
(if (> colon-line-end (point))
(- (current-indentation) c-label-offset)
(current-column))
(if (= (following-char) ?\{) c-brace-offset 0)))))
(+ (if (and (bolp) (zerop c-indent-level))
(+ c-brace-offset c-continued-statement-offset)
c-indent-level)
(progn (skip-chars-backward " \t")
(if (bolp) 0 c-brace-imaginary-offset))
(progn
(if (eq (preceding-char) ?\))
(forward-sexp -1))
(current-indentation))))))))))
(defun c++-backward-to-noncomment (lim)
(let (opoint stop)
(while (not stop)
(skip-chars-backward " \t\n\r\f" lim)
(setq opoint (point))
(cond ((and (>= (point) (+ 2 lim))
(save-excursion
(forward-char -2)
(looking-at "\\*/")))
(search-backward "/*" lim 'move))
((and
(search-backward "//" (max (c++-point-bol) lim) 'move)
(not (c++-within-string-p (point) opoint))))
(t (beginning-of-line)
(skip-chars-forward " \t")
(if (and (looking-at "#") (< (point) opoint))
(setq stop (<= (point) lim))
(setq stop t)
(goto-char opoint)))))))
(defun indent-c++-exp ()
"Indent each line of the C++ grouping following point."
(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
(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)
(setq inner-loop-done nil)
(while (and (not inner-loop-done)
(not (and (eobp) (setq outer-loop-done t))))
(setq ostate state)
(setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
nil nil state))
(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
(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))
(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")
(if (eolp)
nil
(if (and (car indent-stack)
(>= (car indent-stack) 0))
nil
(let (val)
(if (= (char-after (car contain-stack)) ?{)
(save-excursion
(goto-char (car contain-stack))
(setq val (calculate-c-indent-after-brace)))
(setq val (calculate-c++-indent
(if (car indent-stack)
(- (car indent-stack))))))
(setcar indent-stack val)))
(if (/= (char-after (car contain-stack)) ?\{)
(setq this-indent (car indent-stack))
(save-excursion
(setq at-else (looking-at "else\\W"))
(setq at-brace (= (following-char) ?\{))
(c++-backward-to-noncomment opoint)
(if (not (memq (preceding-char) '(nil ?\, ?\ (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))))
(if at-else
(progn (c-backward-to-start-of-if opoint)
(setq this-indent (current-indentation)))
(setq this-indent (car indent-stack))))))
(if (looking-at "\\(public\\|private\\|protected\\):")
(setq this-indent (- this-indent c-indent-level))
(if (or (looking-at "case[ \t]")
(and (looking-at "[A-Za-z]")
(save-excursion
(forward-sexp 1)
(looking-at ":[^:]"))))
(setq this-indent (max 1 (+ this-indent c-label-offset)))))
(if (looking-at "friend[ \t]")
(setq this-indent (+ this-indent c++-friend-offset)))
(if (= (following-char) ?\})
(setq this-indent (- this-indent c-indent-level)))
(if (= (following-char) ?\{)
(setq this-indent (+ this-indent c-brace-offset)))
(or (= (current-column) this-indent)
(= (following-char) ?\#)
(progn
(delete-region (point) (progn (beginning-of-line) (point)))
(indent-to this-indent)))
(or (looking-at comment-start-skip)
(if (re-search-forward comment-start-skip
(save-excursion (end-of-line)
(point)) t)
(progn
(indent-for-comment)
(beginning-of-line))))))))))
(defun fill-c++-comment ()
"Fill a comment contained in consecutive lines containing point.
The fill lines remain a comment."
(interactive)
(save-excursion
(let ((save fill-prefix))
(beginning-of-line 1)
(save-excursion
(re-search-forward comment-start-skip
(save-excursion (end-of-line) (point))
t)
(goto-char (match-end 0))
(set-fill-prefix))
(while (looking-at fill-prefix)
(previous-line 1))
(next-line 1)
(insert-string "\n")
(fill-paragraph nil)
(delete-char -1)
(setq fill-prefix save))))
(defun c++-point-bol ()
"Returns the value of the point at the beginning of the current line."
(save-excursion
(beginning-of-line)
(point)))
(defun c++-within-string-p (point1 point2)
"Returns true if number of double quotes between two points is odd."
(let ((s (buffer-substring point1 point2)))
(not (zerop (% (c++-count-char-in-string ?\" s) 2)))))
(defun c++-count-char-in-string (c s)
(let ((count 0)
(pos 0))
(while (< pos (length s))
(setq count (+ count (if (\= (aref s pos) c) 1 0)))
(setq pos (1+ pos)))
count))
;; rms: This page is creeping featurism, and not worth having.
;;; 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.
(provide 'cplus-md)