*** empty log message ***
[bpt/emacs.git] / lisp / progmodes / cplus-md.el
CommitLineData
c0274f38
ER
1;;; c++-mode.el --- C++ code editing commands for Emacs
2
07168830
ER
3;; Author: Dave Detlefs <dld@cs.cmu.edu>
4;; Stewart Clamen <clamen@cs.cmu.edu>
5;; Maintainer: Dave Detlefs <dld@cs.cmu.edu>
6;; Last-Modified: 09 May 1991
7;; Keywords: c
8
9;;; Commentary:
10
745bc783
JB
11;; 1987 Dave Detlefs (dld@cs.cmu.edu)
12;; and Stewart Clamen (clamen@cs.cmu.edu).
13;; Done by fairly faithful modification of:
14;; c-mode.el, Copyright (C) 1985 Richard M. Stallman.
07168830
ER
15
16;;; Change Log:
17
745bc783
JB
18;; Feb, 1990 (Dave Detlefs, dld@cs.cmu.edu)
19;; Fixed electric-c++-terminator to handle double colons, at the
20;; request of John Hagerman.
21;;
22;; Jan, 1990 (Doug Lea, dl@oswego.edu)
23;; Replaced c++-comment-region and c++-uncomment-region with
24;; versions from Igor Metz that avoid potential infinite loops.
25;;
26;; Oct, 1989 (Dave Detlefs, dld@cs.cmu.edu)
27;; Added contribution from Igor Metz <metz@iam.unibe.ch>:
28;; functions c++-comment-region and c++-uncomment-region and
29;; corresponding key-binding.
30;; Also fixed bug in indentation of second line after an empty
31;; arglist with empty-arglist non-null.
32;;
33;; Sept, 1989 (Glen Ditchfield, gjditchfield@violet.uwaterloo.ca):
34;; Textual changes to more closely imitate Emacs 18.55's c-mode.
35;; Fixed handling of "default:", where ":" was the last character in the
36;; buffer. Fixed indentation of comments starting in column 0, and when
37;; previous line contained more than one comment start string. Fixed
38;; handling of "friend class".
39;;
40;; Aug 7, 1989; John Hagerman (hagerman@ece.cmu.edu):
41;; Changed calculate-c++-indent to handle member initializations
42;; more flexibly. Two new variables are used to control behavior:
43;; c++-member-init-indent and c++-continued-member-init-offset.
44;; Note the assumption that member initializations and argument
45;; declarations are not mixed in one function definition.
46;;
47;; June 1989 (Dave Detlefs, dld@cs.cmu.edu)
48;; Fixed calculate-c++-indent to handle continued lines ending in
49;; {'s. (I wasn't following C-mode closely enough, or C-mode
50;; changed.) Made ' a quote character, at the behest of someone
51;; whose mail I apparently deleted (if they send me mail I'll credit
52;; them here in a future revision.)
53;; Dan Weinreb (dlw@odi.com) pointed out that 'c++-mode successively
54;; bound c++-indent-exp and c++-indent-defun to ESC-^q. ESC-^q is
55;; now bound to c++-indent-exp, while, c++-indent-defun is invoked
56;; with ESC-^x.
57
58;; February 1989 (Dave Detlefs, dld@cs.cmu.edu)
59;; Fixed some errors in c++-indent-defun, as pointed out by Sam
60;; Haradhvala (odi!sam@talcott.harvard.edu).
61;; October 1988 (Dave Detlefs, dld@cs.cmu.edu)
62;; It turns out I had only *thought* I had made
63;; beginning(end)-of-defun work. It should work better now -- you
64;; can either attempt to match defun headers "strongly," using a
65;; very complicated regexp, or "weakly," using a simple one. This
66;; is settable by a variable; the default is the cheaper weak
67;; method. (Stewart Clamen was intimately involved in this, too.)
68;;
69;; I made "'" *not* be a string delimiter, because that was causing
70;; comments containing contractions to ("// don't") to mess up paren
71;; balancing.
72;;
73;; I also incorporated another slight indentation fix from Glen
74;; Ditchfield.
75;;
76;; We hope this is will make into version 19 of gnu-emacs.
77;;
78;; September 1988: incorporated changes from Fred Calm at Schlumberger.
79;; Also, made beginning(end)-of-defun, indent-defun work.
80;;
81;; August 1987: incorporated changes done by Glen Ditchfield of Waterloo.
82
07168830
ER
83;;; Code:
84
745bc783
JB
85(defvar c++-mode-abbrev-table nil
86 "Abbrev table used in C++ mode.")
87(define-abbrev-table 'c++-mode-abbrev-table ())
88
89(defvar c++-mode-map ()
90 "Keymap used in C++ mode.")
91(if c++-mode-map
92 ()
93 (setq c++-mode-map (make-sparse-keymap))
94 (define-key c++-mode-map "\C-j" 'reindent-then-newline-and-indent)
95 (define-key c++-mode-map "{" 'electric-c++-brace)
96 (define-key c++-mode-map "}" 'electric-c++-brace)
97 (define-key c++-mode-map ";" 'electric-c++-semi)
98 (define-key c++-mode-map "\e\C-h" 'mark-c-function)
99 (define-key c++-mode-map "\e\C-q" 'indent-c++-exp)
100 (define-key c++-mode-map "\177" 'backward-delete-char-untabify)
101 (define-key c++-mode-map "\t" 'c++-indent-command)
102 (define-key c++-mode-map "\C-c\C-i" 'c++-insert-header)
103 (define-key c++-mode-map "\C-c\C-\\" 'c++-macroize-region)
104 (define-key c++-mode-map "\C-c\C-c" 'c++-comment-region)
105 (define-key c++-mode-map "\C-c\C-u" 'c++-uncomment-region)
106 (define-key c++-mode-map "\e\C-a" 'c++-beginning-of-defun)
107 (define-key c++-mode-map "\e\C-e" 'c++-end-of-defun)
108 (define-key c++-mode-map "\e\C-x" 'c++-indent-defun))
109
110(defvar c++-mode-syntax-table nil
111 "Syntax table used in C++ mode.")
112
113(if c++-mode-syntax-table
114 ()
115 (setq c++-mode-syntax-table (copy-syntax-table c-mode-syntax-table))
116 (modify-syntax-entry ?/ ". 12" c++-mode-syntax-table)
117 (modify-syntax-entry ?\n ">" c++-mode-syntax-table)
118 (modify-syntax-entry ?\' "." c++-mode-syntax-table))
119
120(defvar c++-continued-member-init-offset nil
121 "*Extra indent for continuation lines of member inits;
122NIL means to align with previous initializations rather than
123with the colon on the first line.")
124(defvar c++-member-init-indent 0
125 "*Indentation level of member initializations in function declarations.")
126(defvar c++-friend-offset -4
127 "*Offset of C++ friend class declarations relative to member declarations.")
128(defvar c++-electric-colon t
129 "*If t, colon is an electric terminator.")
130(defvar c++-empty-arglist-indent nil
131 "*Indicates how far to indent an line following an empty argument
132list. Nil indicates to just after the paren.")
133
134
135;;;###autoload
136(defun c++-mode ()
137 "Major mode for editing C++ code. Very much like editing C code.
138Expression and list commands understand all C++ brackets.
139Tab at left margin indents for C++ code
140Comments are delimited with /* ... */ {or with // ... <newline>}
141Paragraphs are separated by blank lines only.
142Delete converts tabs to spaces as it moves back.
143\\{c++-mode-map}
144Variables controlling indentation style:
145 c-tab-always-indent
146 Non-nil means TAB in C mode should always reindent the current line,
147 regardless of where in the line point is when the TAB command is used.
148 Default is t.
149 c-auto-newline
150 Non-nil means automatically newline before and after braces,
151 and after colons and semicolons, inserted in C code.
152 c-indent-level
153 Indentation of C statements within surrounding block.
154 The surrounding block's indentation is the indentation
155 of the line on which the open-brace appears.
156 c-continued-statement-offset
157 Extra indentation given to a substatement, such as the
158 then-clause of an if or body of a while.
159 c-continued-brace-offset
160 Extra indentation given to a brace that starts a substatement.
161 This is in addition to c-continued-statement-offset.
162 c-brace-offset
163 Extra indentation for line if it starts with an open brace.
164 c-brace-imaginary-offset
165 An open brace following other text is treated as if it were
166 this far to the right of the start of its line.
167 c-argdecl-indent
168 Indentation level of declarations of C function arguments.
169 c-label-offset
170 Extra indentation for line that is a label, or case or ``default:'', or
171 ``public:'' or ``private:'', or ``protected:''.
172 c++-electric-colon
173 If non-nil at invocation of c++-mode (t is the default) colon electricly
174 indents.
175 c++-empty-arglist-indent
176 If non-nil, a function declaration or invocation which ends a line with a
177 left paren is indented this many extra spaces, instead of flush with the
178 left paren.
179 c++-friend-offset
180 Offset of C++ friend class declarations relative to member declarations.
181 c++-member-init-indent
182 Indentation level of member initializations in function declarations,
183 if they are on a separate line beginning with a colon.
184 c++-continued-member-init-offset
185 Extra indentation for continuation lines of member initializations; NIL
186 means to align with previous initializations rather than with the colon.
187
188Settings for K&R, BSD, and Stroustrup indentation styles are
189 c-indent-level 5 8 4
190 c-continued-statement-offset 5 8 4
191 c-continued-brace-offset 0
192 c-brace-offset -5 -8 0
193 c-brace-imaginary-offset 0
194 c-argdecl-indent 0 8 4
195 c-label-offset -5 -8 -4
196 c++-empty-arglist-indent 4
197 c++-friend-offset 0
198
199Turning on C++ mode calls the value of the variable `c++-mode-hook' with
200no args if that value is non-nil."
201 (interactive)
202 (kill-all-local-variables)
203 (use-local-map c++-mode-map)
204 (set-syntax-table c++-mode-syntax-table)
205 (setq major-mode 'c++-mode
206 mode-name "C++"
207 comment-column 32
208 local-abbrev-table c++-mode-abbrev-table)
209 (set (make-local-variable 'indent-line-function) 'c++-indent-line)
210 (set (make-local-variable 'comment-start) "// ")
211 (set (make-local-variable 'comment-end) "")
212 (set (make-local-variable 'comment-start-skip) "/\\*+ *\\|// *")
213 (set (make-local-variable 'comment-indent-hook) 'c++-comment-indent)
214 (set (make-local-variable 'paragraph-start) (concat "^$\\|" page-delimiter))
215 (set (make-local-variable 'paragraph-separate) paragraph-start)
216 (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
217 (set (make-local-variable 'require-final-newline) t)
218 (set (make-local-variable 'parse-sexp-ignore-comments) nil)
219 (run-hooks 'c++-mode-hook)
220 (if c++-electric-colon
221 (define-key c++-mode-map ":" 'electric-c++-terminator)))
222
223;; This is used by indent-for-comment
224;; to decide how much to indent a comment in C++ code
225;; based on its context.
226(defun c++-comment-indent ()
227 (if (looking-at "^\\(/\\*\\|//\\)")
228 0 ; Existing comment at bol stays there.
229 (save-excursion
230 (skip-chars-backward " \t")
231 (max
232 ;; leave at least one space on non-empty lines.
233 (if (zerop (current-column)) 0 (1+ (current-column)))
234 (let ((cur-pt (point)))
235 (beginning-of-line 0)
236 ;; If previous line had a comment, use it's indent
237 (if (re-search-forward comment-start-skip cur-pt t)
238 (progn
239 (goto-char (match-beginning 0))
240 (current-column))
241 comment-column)))))) ; otherwise indent at comment column.
242
243(defun electric-c++-brace (arg)
244 "Insert character and correct line's indentation."
245 (interactive "P")
246 (let (insertpos)
247 (if (and (not arg)
248 (eolp)
249 (or (save-excursion
250 (skip-chars-backward " \t")
251 (bolp))
252 (if c-auto-newline (progn (c++-indent-line) (newline) t))))
253 (progn
254 (insert last-command-char)
255 (c++-indent-line)
256 (if c-auto-newline
257 (progn
258 (newline)
259 ;; (newline) may have done auto-fill
260 (setq insertpos (- (point) 2))
261 (c++-indent-line)))
262 (save-excursion
263 (if insertpos (goto-char (1+ insertpos)))
264 (delete-char -1))))
265 (if insertpos
266 (save-excursion
267 (goto-char insertpos)
268 (self-insert-command (prefix-numeric-value arg)))
269 (self-insert-command (prefix-numeric-value arg)))))
270
271(defun electric-c++-semi (arg)
272 "Insert character and correct line's indentation."
273 (interactive "P")
274 (if c-auto-newline
275 (electric-c++-terminator arg)
276 (self-insert-command (prefix-numeric-value arg))))
277
278(defun electric-c++-terminator (arg)
279 "Insert character and correct line's indentation."
280 (interactive "P")
281 (let (insertpos (end (point)))
282 (if (and (not arg) (eolp)
283 (not (save-excursion
284 (beginning-of-line)
285 (skip-chars-forward " \t")
286 (or (= (following-char) ?#)
287 ;; Colon is special only after a label, or
288 ;; case, or another colon.
289 ;; So quickly rule out most other uses of colon
290 ;; and do no indentation for them.
291 (and (eq last-command-char ?:)
292 (not (looking-at "case[ \t]"))
293 (save-excursion
294 (forward-word 1)
295 (skip-chars-forward " \t")
296 (< (point) end))
297 ;; Do re-indent double colons
298 (save-excursion
299 (end-of-line 1)
300 (looking-at ":")))
301 (progn
302 (beginning-of-defun)
303 (let ((pps (parse-partial-sexp (point) end)))
304 (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))))
305 (progn
306 (insert last-command-char)
307 (c++-indent-line)
308 (and c-auto-newline
309 (not (c-inside-parens-p))
310 (progn
311 ;; the new marker object, used to be just an integer
312 (setq insertpos (make-marker))
313 ;; changed setq to set-marker
314 (set-marker insertpos (1- (point)))
315 ;; do this before the newline, since in auto fill can break
316 (newline)
317 (c-indent-line)))
318 (save-excursion
319 (if insertpos (goto-char (1+ insertpos)))
320 (delete-char -1))))
321 (if insertpos
322 (save-excursion
323 (goto-char insertpos)
324 (self-insert-command (prefix-numeric-value arg)))
325 (self-insert-command (prefix-numeric-value arg)))))
326
327(defun c++-indent-command (&optional whole-exp)
328 "Indent current line as C++ code, or in some cases insert a tab character.
329If `c-tab-always-indent' is non-nil (the default), always indent current
330line. Otherwise, indent the current line only if point is at the left
331margin or in the line's indentation; otherwise insert a tab.
332
333A numeric argument, regardless of its value, means indent rigidly all means
334indent rigidly all the lines of the expression starting after point so that
335this line becomes properly indented. The relative indentation among the
336lines of the expression are preserved."
337 (interactive "P")
338 (if whole-exp
339 ;; If arg, always indent this line as C
340 ;; and shift remaining lines of expression the same amount.
341 (let ((shift-amt (c++-indent-line))
342 beg end)
343 (save-excursion
344 (if c-tab-always-indent
345 (beginning-of-line))
346 (setq beg (point))
347 (forward-sexp 1)
348 (setq end (point))
349 (goto-char beg)
350 (forward-line 1)
351 (setq beg (point)))
352 (if (> end beg)
353 (indent-code-rigidly beg end shift-amt "#")))
354 (if (and (not c-tab-always-indent)
355 (save-excursion
356 (skip-chars-backward " \t")
357 (not (bolp))))
358 (insert-tab)
359 (c++-indent-line))))
360
361(defun c++-indent-line ()
362 "Indent current line as C++ code.
363Return the amount the indentation changed by."
364 (let ((indent (calculate-c++-indent nil))
365 beg shift-amt
366 (case-fold-search nil)
367 (pos (- (point-max) (point))))
368 (beginning-of-line)
369 (setq beg (point))
370 (cond ((eq indent nil)
371 (setq indent (current-indentation)))
372 ((eq indent t)
373 (setq indent (calculate-c-indent-within-comment)))
374 ((looking-at "[ \t]*#")
375 (setq indent 0))
376 (t
377 (skip-chars-forward " \t")
378 (if (listp indent) (setq indent (car indent)))
379 (cond ((looking-at "\\(default\\|public\\|private\\|protected\\):")
380 (setq indent (+ indent c-label-offset)))
381 ((or (looking-at "case\\b")
382 (and (looking-at "[A-Za-z]")
383 (save-excursion
384 (forward-sexp 1)
385 (looking-at ":[^:]"))))
386 (setq indent (max 1 (+ indent c-label-offset))))
387 ((and (looking-at "else\\b")
388 (not (looking-at "else\\s_")))
389 (setq indent (save-excursion
390 (c-backward-to-start-of-if)
391 (current-indentation))))
392 ((looking-at "friend\[ \t]class[ \t]")
393 (setq indent (+ indent c++-friend-offset)))
394 ((= (following-char) ?})
395 (setq indent (- indent c-indent-level)))
396 ((= (following-char) ?{)
397 (setq indent (+ indent c-brace-offset))))))
398 (skip-chars-forward " \t")
399 (setq shift-amt (- indent (current-column)))
400 (if (zerop shift-amt)
401 (if (> (- (point-max) pos) (point))
402 (goto-char (- (point-max) pos)))
403 (delete-region beg (point))
404 (indent-to indent)
405 ;; If initial point was within line's indentation,
406 ;; position after the indentation. Else stay at same point in text.
407 (if (> (- (point-max) pos) (point))
408 (goto-char (- (point-max) pos))))
409 shift-amt))
410
411(defun calculate-c++-indent (&optional parse-start)
412 "Return appropriate indentation for current line as C++ code.
413In usual case returns an integer: the column to indent to.
414Returns nil if line starts inside a string, t if in a comment."
415 (save-excursion
416 (beginning-of-line)
417 (let ((indent-point (point))
418 (case-fold-search nil)
419 state
420 containing-sexp)
421 (if parse-start
422 (goto-char parse-start)
423 (beginning-of-defun))
424 (while (< (point) indent-point)
425 (setq parse-start (point))
426 (setq state (parse-partial-sexp (point) indent-point 0))
427 (setq containing-sexp (car (cdr state))))
428 (cond ((or (nth 3 state) (nth 4 state))
429 ;; return nil or t if should not change this line
430 (nth 4 state))
431 ((null containing-sexp)
432 ;; Line is at top level. May be data or function definition, or
433 ;; may be function argument declaration or member initialization.
434 ;; Indent like the previous top level line unless
435 ;; (1) the previous line ends in a closeparen without semicolon,
436 ;; in which case this line is the first argument declaration or
437 ;; member initialization, or
438 ;; (2) the previous line begins with a colon,
439 ;; in which case this is the second line of member inits.
440 ;; It is assumed that arg decls and member inits are not mixed.
441 (goto-char indent-point)
442 (skip-chars-forward " \t")
443 (if (= (following-char) ?{)
444 0 ; Unless it starts a function body
445 (c++-backward-to-noncomment (or parse-start (point-min)))
446 (if (= (preceding-char) ?\))
447 (progn ; first arg decl or member init
448 (goto-char indent-point)
449 (skip-chars-forward " \t")
450 (if (= (following-char) ?:)
451 c++-member-init-indent
452 c-argdecl-indent))
453 (if (= (preceding-char) ?\;)
454 (backward-char 1))
455 (if (= (preceding-char) ?})
456 0
457 (beginning-of-line) ; continued arg decls or member inits
458 (skip-chars-forward " \t")
459 (if (= (following-char) ?:)
460 (if c++-continued-member-init-offset
461 (+ (current-indentation)
462 c++-continued-member-init-offset)
463 (progn
464 (forward-char 1)
465 (skip-chars-forward " \t")
466 (current-column)))
467 (current-indentation)))
468 )))
469 ((/= (char-after containing-sexp) ?{)
470 ;; line is expression, not statement:
471 ;; indent to just after the surrounding open -- unless
472 ;; empty arg list, in which case we do what
473 ;; c++-empty-arglist-indent says to do.
474 (if (and c++-empty-arglist-indent
475 (or (null (nth 2 state)) ;; indicates empty arg
476 ;; list.
477 ;; Use a heuristic: if the first
478 ;; non-whitespace following left paren on
479 ;; same line is not a comment,
480 ;; is not an empty arglist.
481 (save-excursion
482 (goto-char (1+ containing-sexp))
483 (not
484 (looking-at "\\( \\|\t\\)*[^/\n]")))))
485 (progn
486 (goto-char containing-sexp)
487 (beginning-of-line)
488 (skip-chars-forward " \t")
489 (goto-char (min (+ (point) c++-empty-arglist-indent)
490 (1+ containing-sexp)))
491 (current-column))
492 ;; In C-mode, we would always indent to one after the
493 ;; left paren. Here, though, we may have an
494 ;; empty-arglist, so we'll indent to the min of that
495 ;; and the beginning of the first argument.
496 (goto-char (1+ containing-sexp))
497 (current-column)))
498 (t
499 ;; Statement. Find previous non-comment character.
500 (goto-char indent-point)
501 (c++-backward-to-noncomment containing-sexp)
502 (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?\{)))
503 ;; This line is continuation of preceding line's statement;
504 ;; indent c-continued-statement-offset more than the
505 ;; previous line of the statement.
506 (progn
507 (c-backward-to-start-of-continued-exp containing-sexp)
508 (+ c-continued-statement-offset (current-column)))
509 ;; This line starts a new statement.
510 ;; Position following last unclosed open.
511 (goto-char containing-sexp)
512 ;; Is line first statement after an open-brace?
513 (or
514 ;; If no, find that first statement and indent like it.
515 (save-excursion
516 (forward-char 1)
517 (while (progn (skip-chars-forward " \t\n")
518 (looking-at
519 (concat
520 "#\\|/\\*\\|//"
521 "\\|case[ \t]"
522 "\\|[a-zA-Z0-9_$]*:[^:]"
523 "\\|friend[ \t]class[ \t]")))
524 ;; Skip over comments and labels following openbrace.
525 (cond ((= (following-char) ?\#)
526 (forward-line 1))
527 ((looking-at "/\\*")
528 (search-forward "*/" nil 'move))
529 ((looking-at "//\\|friend[ \t]class[ \t]")
530 (forward-line 1))
531 (t
532 (re-search-forward ":[^:]" nil 'move))))
533 ;; The first following code counts
534 ;; if it is before the line we want to indent.
535 (and (< (point) indent-point)
536 (current-column)))
537 ;; If no previous statement,
538 ;; indent it relative to line brace is on.
539 ;; For open brace in column zero, don't let statement
540 ;; start there too. If c-indent-offset is zero,
541 ;; use c-brace-offset + c-continued-statement-offset instead.
542 ;; For open-braces not the first thing in a line,
543 ;; add in c-brace-imaginary-offset.
544 (+ (if (and (bolp) (zerop c-indent-level))
545 (+ c-brace-offset c-continued-statement-offset)
546 c-indent-level)
547 ;; Move back over whitespace before the openbrace.
548 ;; If openbrace is not first nonwhite thing on the line,
549 ;; add the c-brace-imaginary-offset.
550 (progn (skip-chars-backward " \t")
551 (if (bolp) 0 c-brace-imaginary-offset))
552 ;; If the openbrace is preceded by a parenthesized exp,
553 ;; move to the beginning of that;
554 ;; possibly a different line
555 (progn
556 (if (eq (preceding-char) ?\))
557 (forward-sexp -1))
558 ;; Get initial indentation of the line we are on.
559 (current-indentation))))))))))
560
561(defun c++-backward-to-noncomment (lim)
562 (let (opoint stop)
563 (while (not stop)
564 (skip-chars-backward " \t\n\r\f" lim)
565 (setq opoint (point))
566 (cond ((and (>= (point) (+ 2 lim))
567 (save-excursion
568 (forward-char -2)
569 (looking-at "\\*/")))
570 (search-backward "/*" lim 'move))
571 ((and
572 (search-backward "//" (max (point-bol) lim) 'move)
573 (not (within-string-p (point) opoint))))
574 (t (beginning-of-line)
575 (skip-chars-forward " \t")
576 (if (looking-at "#")
577 (setq stop (<= (point) lim))
578 (setq stop t)
579 (goto-char opoint)))))))
580
581(defun indent-c++-exp ()
582 "Indent each line of the C++ grouping following point."
583 (interactive)
584 (let ((indent-stack (list nil))
585 (contain-stack (list (point)))
586 (case-fold-search nil)
587 restart outer-loop-done inner-loop-done state ostate
588 this-indent last-sexp
589 at-else at-brace
590 (opoint (point))
591 (next-depth 0))
592 (save-excursion
593 (forward-sexp 1))
594 (save-excursion
595 (setq outer-loop-done nil)
596 (while (and (not (eobp)) (not outer-loop-done))
597 (setq last-depth next-depth)
598 ;; Compute how depth changes over this line
599 ;; plus enough other lines to get to one that
600 ;; does not end inside a comment or string.
601 ;; Meanwhile, do appropriate indentation on comment lines.
602 (setq innerloop-done nil)
603 (while (and (not innerloop-done)
604 (not (and (eobp) (setq outer-loop-done t))))
605 (setq ostate state)
606 (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
607 nil nil state))
608 (setq next-depth (car state))
609 (if (and (car (cdr (cdr state)))
610 (>= (car (cdr (cdr state))) 0))
611 (setq last-sexp (car (cdr (cdr state)))))
612 (if (or (nth 4 ostate))
613 (c++-indent-line))
614 (if (or (nth 3 state))
615 (forward-line 1)
616 (setq innerloop-done t)))
617 (if (<= next-depth 0)
618 (setq outer-loop-done t))
619 (if outer-loop-done
620 nil
621 ;; If this line had ..))) (((.. in it, pop out of the levels
622 ;; that ended anywhere in this line, even if the final depth
623 ;; doesn't indicate that they ended.
624 (while (> last-depth (nth 6 state))
625 (setq indent-stack (cdr indent-stack)
626 contain-stack (cdr contain-stack)
627 last-depth (1- last-depth)))
628 (if (/= last-depth next-depth)
629 (setq last-sexp nil))
630 ;; Add levels for any parens that were started in this line.
631 (while (< last-depth next-depth)
632 (setq indent-stack (cons nil indent-stack)
633 contain-stack (cons nil contain-stack)
634 last-depth (1+ last-depth)))
635 (if (null (car contain-stack))
636 (setcar contain-stack (or (car (cdr state))
637 (save-excursion (forward-sexp -1)
638 (point)))))
639 (forward-line 1)
640 (skip-chars-forward " \t")
641 (if (eolp)
642 nil
643 (if (and (car indent-stack)
644 (>= (car indent-stack) 0))
645 ;; Line is on an existing nesting level.
646 ;; Lines inside parens are handled specially.
647 (if (/= (char-after (car contain-stack)) ?{)
648 (setq this-indent (car indent-stack))
649 ;; Line is at statement level.
650 ;; Is it a new statement? Is it an else?
651 ;; Find last non-comment character before this line
652 (save-excursion
653 (setq at-else (looking-at "else\\W"))
654 (setq at-brace (= (following-char) ?{))
655 (c++-backward-to-noncomment opoint)
656 (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?{)))
657 ;; Preceding line did not end in comma or semi;
658 ;; indent this line c-continued-statement-offset
659 ;; more than previous.
660 (progn
661 (c-backward-to-start-of-continued-exp
662 (car contain-stack))
663 (setq this-indent
664 (+ c-continued-statement-offset
665 (current-column)
666 (if at-brace c-continued-brace-offset 0))))
667 ;; Preceding line ended in comma or semi;
668 ;; use the standard indent for this level.
669 (if at-else
670 (progn (c-backward-to-start-of-if opoint)
671 (setq this-indent (current-indentation)))
672 (setq this-indent (car indent-stack))))))
673 ;; Just started a new nesting level.
674 ;; Compute the standard indent for this level.
675 (let ((val (calculate-c++-indent
676 (if (car indent-stack)
677 (- (car indent-stack))))))
678 (setcar indent-stack
679 (setq this-indent val))))
680 ;; Adjust line indentation according to its contents
681 (if (looking-at "\\(public\\|private\\|protected\\):")
682 (setq this-indent (- this-indent c-indent-level)))
683 (if (or (looking-at "case[ \t]")
684 (and (looking-at "[A-Za-z]")
685 (save-excursion
686 (forward-sexp 1)
687 (looking-at ":[^:]"))))
688 (setq this-indent (max 1 (+ this-indent c-label-offset))))
689 (if (looking-at "friend[ \t]class[ \t]")
690 (setq this-indent (+ this-indent c++-friend-offset)))
691 (if (= (following-char) ?})
692 (setq this-indent (- this-indent c-indent-level)))
693 (if (= (following-char) ?{)
694 (setq this-indent (+ this-indent c-brace-offset)))
695 ;; Put chosen indentation into effect.
696 (or (= (current-column) this-indent)
697 (= (following-char) ?\#)
698 (progn
699 (delete-region (point) (progn (beginning-of-line) (point)))
700 (indent-to this-indent)))
701 ;; Indent any comment following the text.
702 (or (looking-at comment-start-skip)
703 (if (re-search-forward comment-start-skip
704 (save-excursion (end-of-line)
705 (point)) t)
706 (progn
707 (indent-for-comment)
708 (beginning-of-line))))))))))
709
710(defun fill-C-comment ()
711 (interactive)
712 (save-excursion
713 (let ((save fill-prefix))
714 (beginning-of-line 1)
715 (save-excursion
716 (re-search-forward comment-start-skip
717 (save-excursion (end-of-line) (point))
718 t)
719 (goto-char (match-end 0))
720 (set-fill-prefix))
721 (while (looking-at fill-prefix)
722 (previous-line 1))
723 (next-line 1)
724 (insert-string "\n")
725 (fill-paragraph nil)
726 (delete-char -1)
727 (setq fill-prefix save))))
728
729(defun point-bol ()
730 "Returns the value of the point at the beginning of the current line."
731 (save-excursion
732 (beginning-of-line)
733 (point)))
734
735(defun c++-insert-header ()
736 "Insert header denoting C++ code at top of buffer."
737 (interactive)
738 (save-excursion
739 (goto-char (point-min))
740 (insert "// "
741 "This may look like C code, but it is really "
742 "-*- C++ -*-"
743 "\n\n")))
744
745(defun within-string-p (point1 point2)
746 "Returns true if number of double quotes between two points is odd."
747 (let ((s (buffer-substring point1 point2)))
748 (not (zerop (mod (count-char-in-string ?\" s) 2)))))
749
750(defun count-char-in-string (c s)
751 (let ((count 0)
752 (pos 0))
753 (while (< pos (length s))
754 (setq count (+ count (if (\= (aref s pos) c) 1 0)))
755 (setq pos (1+ pos)))
756 count))
757\f
758;;; This page covers "macroization;" making C++ parameterized types
759;;; via macros.
760
761(defvar c++-default-macroize-column 78
762 "Place to insert backslashes.")
763
764(defun c++-macroize-region (from to arg)
765 "Insert backslashes at end of every line in region. Useful for defining cpp
766macros. If called with negative argument, will remove trailing backslashes,
767so that indentation will work right."
768 (interactive "r\np")
769 (save-excursion
770 (goto-char from)
771 (beginning-of-line 1)
772 (let ((line (count-lines (point-min) (point)))
773 (to-line (save-excursion (goto-char to)
774 (count-lines (point-min) (point)))))
775 (while (< line to-line)
776 (backslashify-current-line (> arg 0))
777 (next-line 1) (setq line (1+ line))))))
778
779(defun backslashify-current-line (doit)
780 (end-of-line 1)
781 (cond
782 (doit
783 ;; Note that "\\\\" is needed to get one backslash.
784 (if (not (save-excursion (forward-char -1) (looking-at "\\\\")))
785 (progn
786 (if (>= (current-column) c++-default-macroize-column)
787 (insert " \\")
788 (while (<= (current-column) c++-default-macroize-column)
789 (insert "\t") (end-of-line))
790 (delete-char -1)
791 (while (< (current-column) c++-default-macroize-column)
792 (insert " ") (end-of-line))
793 (insert "\\")))))
794 (t
795 (forward-char -1)
796 (if (looking-at "\\\\")
797 (progn (skip-chars-backward " \t")
798 (kill-line))))))
799
800\f
801;;; This page covers commenting out multiple lines.
802
803(defun c++-comment-region ()
804 "Comment out all lines in a region between mark and current point.
805Inserts \"// \" (`comment-start') in front of each line."
806 (interactive)
807 (let* ((m (if (eq (mark) nil) (error "Mark is not set!") (mark)))
808 (start (if (< (point) m) (point) m))
809 (end (if (> (point) m) (point) m))
810 (mymark (copy-marker end)))
811 (save-excursion
812 (goto-char start)
813 (while (< (point) (marker-position mymark))
814 (beginning-of-line)
815 (insert comment-start)
816 (beginning-of-line)
817 (next-line 1)))))
818
819(defun c++-uncomment-region ()
820 "Uncomment all lines in region between mark and current point.
821Deletes the leading \"// \" (`comment-start') from each line, if any."
822 (interactive)
823 (let* ((m (if (eq (mark) nil) (error "Mark is not set!") (mark)))
824 (start (if (< (point) m) (point) m))
825 (end (if (> (point) m) (point) m))
826 (mymark (copy-marker end))
827 (len (length comment-start))
828 (char (string-to-char comment-start)))
829 (save-excursion
830 (goto-char start)
831 (while (< (point) (marker-position mymark))
832 (beginning-of-line)
833 (if (looking-at (concat " *" comment-start))
834 (progn
835 (zap-to-char 1 char)
836 (delete-char len)))
837 (beginning-of-line)
838 (next-line 1)))))
839\f
840;;; Below are two regular expressions that attempt to match defuns
841;;; "strongly" and "weakly." The strong one almost reconstructs the
842;;; grammar of C++; the weak one just figures anything id or curly on
843;;; the left begins a defun. The constant "c++-match-header-strongly"
844;;; determines which to use; the default is the weak one.
845
846(defvar c++-match-header-strongly nil
847 "*If nil, use `c++-defun-header-weak' to identify beginning of definitions.
848If non-nil, use `c++-defun-header-strong'.")
849
850(defvar c++-defun-header-strong-struct-equivs "\\(class\\|struct\\|enum\\)"
851 "Regexp to match names of structure declaration blocks in C++.")
852
853(defconst c++-defun-header-strong
854 (let*
855 (; valid identifiers
856 ;; There's a real wierdness here -- if I switch the below
857 (id "\\(\\w\\|_\\)+")
858 ;; to be
859 ;; (id "\\(_\\|\\w\\)+")
860 ;; things no longer work right. Try it and see!
861
862 ; overloadable operators
863 (op-sym1
864 "[---+*/%^&|~!=<>]\\|[---+*/%^&|<>=!]=\\|<<=?\\|>>=?")
865 (op-sym2
866 "&&\\|||\\|\\+\\+\\|--\\|()\\|\\[\\]")
867 (op-sym (concat "\\(" op-sym1 "\\|" op-sym2 "\\)"))
868 ; whitespace
869 (middle "[^\\*]*\\(\\*+[^/\\*][^\\*]*\\)*")
870 (c-comment (concat "/\\*" middle "\\*+/"))
871 (wh (concat "\\(\\s \\|\n\\|//.*$\\|" c-comment "\\)"))
872 (wh-opt (concat wh "*"))
873 (wh-nec (concat wh "+"))
874 (oper (concat "\\(" "operator" "\\("
875 wh-opt op-sym "\\|" wh-nec id "\\)" "\\)"))
876 (dcl-list "([^():]*)")
877 (func-name (concat "\\(" oper "\\|" id "::" id "\\|" id "\\)"))
878 (inits
879 (concat "\\(:"
880 "\\(" wh-opt id "(.*\\()" wh-opt "," "\\)\\)*"
881 wh-opt id "(.*)" wh-opt "{"
882 "\\|" wh-opt "{\\)"))
883 (type-name (concat
884 "\\(" c++-defun-header-strong-struct-equivs wh-nec "\\)?"
885 id))
886 (type (concat "\\(const" wh-nec "\\)?"
887 "\\(" type-name "\\|" type-name wh-opt "\\*+" "\\|"
888 type-name wh-opt "&" "\\)"))
889 (modifier "\\(inline\\|virtual\\|overload\\|auto\\|static\\)")
890 (modifiers (concat "\\(" modifier wh-nec "\\)*"))
891 (func-header
892 ;; type arg-dcl
893 (concat modifiers type wh-nec func-name wh-opt dcl-list wh-opt inits))
894 (inherit (concat "\\(:" wh-opt "\\(public\\|private\\)?"
895 wh-nec id "\\)"))
896 (cs-header (concat
897 c++-defun-header-strong-struct-equivs
898 wh-nec id wh-opt inherit "?" wh-opt "{")))
899 (concat "^\\(" func-header "\\|" cs-header "\\)"))
900 "Strongly-defined regexp to match beginning of structure or function def.")
901
902
903;; This part has to do with recognizing defuns.
904
905;; The weak convention we will use is that a defun begins any time
906;; there is a left curly brace, or some identifier on the left margin,
907;; followed by a left curly somewhere on the line. (This will also
908;; incorrectly match some continued strings, but this is after all
909;; just a weak heuristic.) Suggestions for improvement (short of the
910;; strong scheme shown above) are welcomed.
911
912(defconst c++-defun-header-weak "^{\\|^[_a-zA-Z].*{"
913 "Weakly-defined regexp to match beginning of structure or function def.")
914
915(defun c++-beginning-of-defun (arg)
916 (interactive "p")
917 (let ((c++-defun-header (if c++-match-header-strongly
918 c++-defun-header-strong
919 c++-defun-header-weak)))
920 (cond ((or (= arg 0) (and (> arg 0) (bobp))) nil)
921 ((and (not (looking-at c++-defun-header))
922 (let ((curr-pos (point))
923 (open-pos (if (search-forward "{" nil 'move)
924 (point)))
925 (beg-pos
926 (if (re-search-backward c++-defun-header nil 'move)
927 (match-beginning 0))))
928 (if (and open-pos beg-pos
929 (< beg-pos curr-pos)
930 (> open-pos curr-pos))
931 (progn
932 (goto-char beg-pos)
933 (if (= arg 1) t nil));; Are we done?
934 (goto-char curr-pos)
935 nil))))
936 (t
937 (if (and (looking-at c++-defun-header) (not (bobp)))
938 (forward-char (if (< arg 0) 1 -1)))
939 (and (re-search-backward c++-defun-header nil 'move (or arg 1))
940 (goto-char (match-beginning 0)))))))
941
942
943(defun c++-end-of-defun (arg)
944 (interactive "p")
945 (let ((c++-defun-header (if c++-match-header-strongly
946 c++-defun-header-strong
947 c++-defun-header-weak)))
948 (if (and (eobp) (> arg 0))
949 nil
950 (if (and (> arg 0) (looking-at c++-defun-header)) (forward-char 1))
951 (let ((pos (point)))
952 (c++-beginning-of-defun
953 (if (< arg 0)
954 (- (- arg (if (eobp) 0 1)))
955 arg))
956 (if (and (< arg 0) (bobp))
957 t
958 (if (re-search-forward c++-defun-header nil 'move)
959 (progn (forward-char -1)
960 (forward-sexp)
961 (beginning-of-line 2)))
962 (if (and (= pos (point))
963 (re-search-forward c++-defun-header nil 'move))
964 (c++-end-of-defun 1))))
965 t)))
966
967(defun c++-indent-defun ()
968 "Indents the current function definition, struct or class declaration."
969 (interactive)
970 (let ((restore (point)))
971 (c++-end-of-defun 1)
972 (beginning-of-line 1)
973 (let ((end (point)))
974 (c++-beginning-of-defun 1)
975 (while (<= (point) end)
976 (c++-indent-line)
977 (next-line 1)
978 (beginning-of-line 1)))
979 (goto-char restore)))
c0274f38
ER
980
981;;; c++-mode.el ends here