|
|
1.1 root 1: ;; C code editing commands for Emacs
2: ;; Copyright (C) 1985 Richard M. Stallman.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is distributed in the hope that it will be useful,
7: ;; but WITHOUT ANY WARRANTY. No author or distributor
8: ;; accepts responsibility to anyone for the consequences of using it
9: ;; or for whether it serves any particular purpose or works at all,
10: ;; unless he says so in writing. Refer to the GNU Emacs General Public
11: ;; License for full details.
12:
13: ;; Everyone is granted permission to copy, modify and redistribute
14: ;; GNU Emacs, but only under the conditions described in the
15: ;; GNU Emacs General Public License. A copy of this license is
16: ;; supposed to have been given to you along with GNU Emacs so you
17: ;; can know your rights and responsibilities. It should be in a
18: ;; file named COPYING. Among other things, the copyright notice
19: ;; and this notice must be preserved on all copies.
20:
21:
22: (defvar c-mode-syntax-table nil
23: "Syntax table in use in C-mode buffers.")
24: (defvar c-mode-abbrev-table nil
25: "Abbrev table in use in C-mode buffers.")
26:
27: (defvar c-mode-map (make-sparse-keymap)
28: "Keymap used in C mode.")
29:
30: (define-key c-mode-map "\C-j" 'reindent-then-newline-and-indent)
31: (define-key c-mode-map "{" 'electric-c-brace)
32: (define-key c-mode-map "}" 'electric-c-brace)
33: (define-key c-mode-map ";" 'electric-c-semi)
34: (define-key c-mode-map ":" 'electric-c-terminator)
35: (define-key c-mode-map "\e\C-h" 'mark-c-function)
36: (define-key c-mode-map "\e\C-q" 'indent-c-exp)
37: (define-key c-mode-map "\177" 'backward-delete-char-untabify)
38: (define-key c-mode-map "\t" 'c-indent-line)
39:
40: (defconst c-indent-level 2
41: "*Indentation of C statements with respect to containing block.")
42: (defconst c-brace-imaginary-offset 0
43: "*Imagined indentation of a C open brace that actually follows a statement.")
44: (defconst c-brace-offset 0
45: "*Extra indentation for braces, compared with other text in same context.")
46: (defconst c-argdecl-indent 5
47: "*Indentation level of declarations of C function arguments.")
48: (defconst c-label-offset -2
49: "*Offset of C label lines and case statements relative to usual indentation.")
50: (defconst c-continued-statement-offset 2
51: "*Extra indent for lines not starting new statements.")
52:
53: (defconst c-auto-newline nil
54: "*Non-nil means automatically newline before and after braces,
55: and after colons and semicolons, inserted in C code.")
56:
57: (defun c-mode ()
58: "Major mode for editing C code.
59: Expression and list commands understand all C brackets.
60: Tab indents for C code.
61: Comments are delimited with /* ... */.
62: Paragraphs are separated by blank lines only.
63: Delete converts tabs to spaces as it moves back.
64: \\{c-mode-map}
65: Variables controlling indentation style:
66: c-auto-newline
67: Non-nil means automatically newline before and after braces,
68: and after colons and semicolons, inserted in C code.
69: c-indent-level
70: Indentation of C statements within surrounding block.
71: The surrounding block's indentation is the indentation
72: of the line on which the open-brace appears.
73: c-continued-statement-offset
74: Extra indentation given to a substatement, such as the
75: then-clause of an if or body of a while.
76: c-brace-offset
77: Extra indentation for line if it starts with an open brace.
78: c-brace-imaginary-offset
79: An open brace following other text is treated as if it were
80: this far to the right of the start of its line.
81: c-argdecl-indent
82: Indentation level of declarations of C function arguments.
83: c-label-offset
84: Extra indentation for line that is a label, or case or default.
85:
86: Turning on C mode calls the value of the variable c-mode-hook with no args,
87: if that value is non-nil."
88: (interactive)
89: (kill-all-local-variables)
90: (use-local-map c-mode-map)
91: (setq major-mode 'c-mode)
92: (setq mode-name "C")
93: (define-abbrev-table 'c-mode-abbrev-table ())
94: (setq local-abbrev-table c-mode-abbrev-table)
95: (if (not c-mode-syntax-table)
96: (let ((i 0))
97: (setq c-mode-syntax-table (make-syntax-table))
98: (set-syntax-table c-mode-syntax-table)
99: (modify-syntax-entry ?\\ "\\")
100: (modify-syntax-entry ?/ ". 14")
101: (modify-syntax-entry ?* ". 23")
102: (modify-syntax-entry ?+ ".")
103: (modify-syntax-entry ?- ".")
104: (modify-syntax-entry ?= ".")
105: (modify-syntax-entry ?% ".")
106: (modify-syntax-entry ?< ".")
107: (modify-syntax-entry ?> ".")
108: (modify-syntax-entry ?\' "\""))
109: (set-syntax-table c-mode-syntax-table))
110: (make-local-variable 'paragraph-start)
111: (setq paragraph-start (concat "^$\\|" page-delimiter))
112: (make-local-variable 'paragraph-separate)
113: (setq paragraph-separate paragraph-start)
114: (make-local-variable 'indent-line-function)
115: (setq indent-line-function 'c-indent-line)
116: (make-local-variable 'require-final-newline)
117: (setq require-final-newline t)
118: (make-local-variable 'comment-start)
119: (setq comment-start "/* ")
120: (make-local-variable 'comment-end)
121: (setq comment-end " */")
122: (make-local-variable 'comment-column)
123: (setq comment-column 32)
124: (make-local-variable 'comment-start-skip)
125: (setq comment-start-skip "/\\*+ *")
126: (make-local-variable 'comment-indent-hook)
127: (setq comment-indent-hook 'c-comment-indent)
128: (make-local-variable 'parse-sexp-ignore-comments)
129: (setq parse-sexp-ignore-comments t)
130: (run-hooks 'c-mode-hook))
131:
132: ;; This is used by indent-for-comment
133: ;; to decide how much to indent a comment in C code
134: ;; based on its context.
135: (defun c-comment-indent ()
136: (if (looking-at "^/\\*")
137: 0 ;Existing comment at bol stays there.
138: (save-excursion
139: (skip-chars-backward " \t")
140: (max (1+ (current-column)) ;Else indent at comment column
141: comment-column)))) ; except leave at least one space.
142:
143: (defun electric-c-brace (arg)
144: "Insert character and correct line's indentation."
145: (interactive "P")
146: (let (insertpos)
147: (if (and (not arg)
148: (eolp)
149: (or (save-excursion
150: (skip-chars-backward " \t")
151: (bolp))
152: (if c-auto-newline (progn (c-indent-line) (newline) t) nil)))
153: (progn
154: (insert last-command-char)
155: (c-indent-line nil)
156: (if c-auto-newline
157: (progn
158: (setq insertpos (1- (point)))
159: (newline)
160: (c-indent-line nil)))
161: (save-excursion
162: (if insertpos (goto-char (1+ insertpos)))
163: (delete-char -1))))
164: (if insertpos
165: (save-excursion
166: (goto-char insertpos)
167: (self-insert-command (prefix-numeric-value arg)))
168: (self-insert-command (prefix-numeric-value arg)))))
169:
170: (defun electric-c-semi (arg)
171: "Insert character and correct line's indentation."
172: (interactive "P")
173: (if c-auto-newline
174: (electric-c-terminator arg)
175: (self-insert-command (prefix-numeric-value arg))))
176:
177: (defun electric-c-terminator (arg)
178: "Insert character and correct line's indentation."
179: (interactive "P")
180: (let (insertpos (end (point)))
181: (if (and (not arg) (eolp)
182: (not (save-excursion
183: (beginning-of-line)
184: (skip-chars-forward " \t")
185: (or (= (following-char) ?#)
186: (let ((pps (parse-partial-sexp (point) end)))
187: (or (nth 3 pps) (nth 4 pps) (nth 5 pps)))))))
188: (progn
189: (insert last-command-char)
190: (c-indent-line nil)
191: (and c-auto-newline
192: (not (c-inside-parens-p))
193: (progn
194: (setq insertpos (1- (point)))
195: (newline)
196: (c-indent-line nil)))
197: (save-excursion
198: (if insertpos (goto-char (1+ insertpos)))
199: (delete-char -1))))
200: (if insertpos
201: (save-excursion
202: (goto-char insertpos)
203: (self-insert-command (prefix-numeric-value arg)))
204: (self-insert-command (prefix-numeric-value arg)))))
205:
206: (defun c-inside-parens-p ()
207: (condition-case ()
208: (save-excursion
209: (save-restriction
210: (narrow-to-region (point)
211: (progn (beginning-of-defun) (point)))
212: (goto-char (point-max))
213: (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))
214: (error nil)))
215:
216: (defun c-indent-line (&optional whole-exp)
217: "Indent current line as C code.
218: Argument means shift any additional lines of grouping
219: rigidly with thls line."
220: (interactive "P")
221: (let ((indent (calculate-c-indent nil))
222: beg end shift-amt
223: (case-fold-search nil)
224: (pos (- (point-max) (point))))
225: (beginning-of-line)
226: (setq beg (point))
227: (cond ((eq indent nil)
228: (setq indent (current-indentation)))
229: ((eq indent t)
230: (setq indent (calculate-c-indent-within-comment)))
231: ((looking-at "[ \t]*#")
232: (setq indent 0))
233: (t
234: (skip-chars-forward " \t")
235: (if (listp indent) (setq indent (car indent)))
236: (cond ((or (looking-at "case\\b")
237: (and (looking-at "[A-Za-z]")
238: (save-excursion
239: (forward-sexp 1)
240: (looking-at ":"))))
241: (setq indent (max 1 (+ indent c-label-offset))))
242: ((looking-at "else\\b")
243: (setq indent (save-excursion
244: (c-backward-to-start-of-if)
245: (current-indentation))))
246: ((= (following-char) ?})
247: (setq indent (- indent c-indent-level)))
248: ((= (following-char) ?{)
249: (setq indent (+ indent c-brace-offset))))))
250: (skip-chars-forward " \t")
251: (setq shift-amt (- indent (current-column)))
252: (if (zerop shift-amt)
253: (if (> (- (point-max) pos) (point))
254: (goto-char (- (point-max) pos)))
255: (delete-region beg (point))
256: (indent-to indent)
257: ;; If initial point was within line's indentation,
258: ;; position after the indentation. Else stay at same point in text.
259: (if (> (- (point-max) pos) (point))
260: (goto-char (- (point-max) pos)))
261: ;; If desired, shift remaining lines of expression the same amount.
262: (and whole-exp
263: (save-excursion
264: (goto-char beg)
265: (forward-sexp 1)
266: (setq end (point))
267: (goto-char beg)
268: (forward-line 1)
269: (setq beg (point))
270: (> end beg))
271: (indent-code-rigidly beg end shift-amt "#")))))
272:
273: (defun calculate-c-indent (&optional parse-start)
274: "Return appropriate indentation for current line as C code.
275: In usual case returns an integer: the column to indent to.
276: Returns nil if line starts inside a string, t if in a comment."
277: (save-excursion
278: (beginning-of-line)
279: (let ((indent-point (point))
280: (case-fold-search nil)
281: state
282: containing-sexp)
283: (if parse-start
284: (goto-char parse-start)
285: (beginning-of-defun))
286: (while (< (point) indent-point)
287: (setq parse-start (point))
288: (setq state (parse-partial-sexp (point) indent-point 0))
289: (setq containing-sexp (car (cdr state))))
290: (cond ((or (nth 3 state) (nth 4 state))
291: ;; return nil or t if should not change this line
292: (nth 4 state))
293: ((null containing-sexp)
294: ;; Line is at top level. May be data or function definition,
295: ;; or may be function argument declaration.
296: ;; Indent like the previous top level line
297: ;; unless that ends in a closeparen without semicolon,
298: ;; in which case this line is the first argument decl.
299: (goto-char indent-point)
300: (skip-chars-forward " \t")
301: (if (= (following-char) ?{)
302: 0 ; Unless it starts a function body
303: (c-backward-to-noncomment (or parse-start (point-min)))
304: (if (= (preceding-char) ?\))
305: c-argdecl-indent
306: (current-indentation))))
307: ((/= (char-after containing-sexp) ?{)
308: ;; line is expression, not statement:
309: ;; indent to just after the surrounding open.
310: (goto-char (1+ containing-sexp))
311: (current-column))
312: (t
313: ;; Statement. Find previous non-comment character.
314: (goto-char indent-point)
315: (c-backward-to-noncomment containing-sexp)
316: (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?\{)))
317: ;; This line is continuation of preceding line's statement;
318: ;; indent c-continued-statement-offset more than the
319: ;; previous line of the statement.
320: (progn
321: (c-backward-to-start-of-continued-exp containing-sexp)
322: (+ c-continued-statement-offset (current-column)))
323: ;; This line starts a new statement.
324: ;; Position following last unclosed open.
325: (goto-char containing-sexp)
326: ;; Is line first statement after an open-brace?
327: (or
328: ;; If no, find that first statement and indent like it.
329: (save-excursion
330: (forward-char 1)
331: (while (progn (skip-chars-forward " \t\n")
332: (looking-at "#\\|/\\*\\|case[ \t\n]\\|[a-zA-Z0-9_$]*:"))
333: ;; Skip over comments and labels following openbrace.
334: (if (= (following-char) ?\#)
335: (forward-line 1)
336: (if (looking-at "/\\*")
337: (search-forward "*/" nil 'move)
338: (search-forward ":"))))
339: ;; The first following code counts
340: ;; if it is before the line we want to indent.
341: (and (< (point) indent-point)
342: (current-column)))
343: ;; If no previous statement,
344: ;; indent it relative to line brace is on.
345: ;; For open brace in column zero, don't let statement
346: ;; start there too. If c-indent-offset is zero,
347: ;; use c-brace-offset + c-continued-statement-offset instead.
348: ;; For open-braces not the first thing in a line,
349: ;; add in c-brace-imaginary-offset.
350: (+ (if (and (bolp) (zerop c-indent-level))
351: (+ c-brace-offset c-continued-statement-offset)
352: c-indent-level)
353: (if (save-excursion (skip-chars-backward " \t")
354: (bolp))
355: 0 c-brace-imaginary-offset)
356: (current-indentation)))))))))
357:
358: (defun calculate-c-indent-within-comment ()
359: "Return the indentation amount for line, assuming that
360: the current line is to be regarded as part of a block comment."
361: (let (end star-start)
362: (save-excursion
363: (beginning-of-line)
364: (skip-chars-forward " \t")
365: (setq star-start (= (following-char) ?\*))
366: (skip-chars-backward " \t\n")
367: (setq end (point))
368: (beginning-of-line)
369: (skip-chars-forward " \t")
370: (and (re-search-forward "/\\*[ \t]*" end t)
371: star-start
372: (goto-char (1+ (match-beginning 0))))
373: (current-column))))
374:
375:
376: (defun c-backward-to-noncomment (lim)
377: (let (opoint stop)
378: (while (not stop)
379: (skip-chars-backward " \t\n" lim)
380: (setq opoint (point))
381: (if (and (>= (point) (+ 2 lim))
382: (save-excursion
383: (forward-char -2)
384: (looking-at "\\*/")))
385: (search-backward "/*" lim 'move)
386: (beginning-of-line)
387: (skip-chars-forward " \t")
388: (if (looking-at "#")
389: (setq stop (<= (point) lim))
390: (setq stop t)
391: (goto-char opoint))))))
392:
393: (defun c-backward-to-start-of-continued-exp (lim)
394: (if (= (preceding-char) ?\))
395: (forward-sexp -1))
396: (beginning-of-line)
397: (if (<= (point) lim)
398: (goto-char (1+ lim)))
399: (skip-chars-forward " \t"))
400:
401: (defun c-backward-to-start-of-if (&optional limit)
402: "Move to the start of the last ``unbalanced'' if."
403: (or limit (setq limit (save-excursion (beginning-of-defun) (point))))
404: (let ((if-level 1)
405: (case-fold-search nil))
406: (while (not (zerop if-level))
407: (backward-sexp 1)
408: (cond ((looking-at "else\\b")
409: (setq if-level (1+ if-level)))
410: ((looking-at "if\\b")
411: (setq if-level (1- if-level)))
412: ((< (point) limit)
413: (setq if-level 0)
414: (goto-char limit))))))
415:
416:
417: (defun mark-c-function ()
418: "Put mark at end of C function, point at beginning."
419: (interactive)
420: (push-mark (point))
421: (end-of-defun)
422: (push-mark (point))
423: (beginning-of-defun)
424: (backward-paragraph))
425:
426: (defun indent-c-exp ()
427: "Indent each line of the C grouping following point."
428: (interactive)
429: (let ((indent-stack (list nil))
430: (contain-stack (list (point)))
431: (case-fold-search nil)
432: restart outer-loop-done inner-loop-done state ostate
433: this-indent last-sexp
434: at-else
435: (opoint (point))
436: (next-depth 0))
437: (save-excursion
438: (forward-sexp 1))
439: (save-excursion
440: (setq outer-loop-done nil)
441: (while (and (not (eobp)) (not outer-loop-done))
442: (setq last-depth next-depth)
443: ;; Compute how depth changes over this line
444: ;; plus enough other lines to get to one that
445: ;; does not end inside a comment or string.
446: ;; Meanwhile, do appropriate indentation on comment lines.
447: (setq innerloop-done nil)
448: (while (and (not innerloop-done)
449: (not (and (eobp) (setq outer-loop-done t))))
450: (setq ostate state)
451: (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
452: nil nil state))
453: (setq next-depth (car state))
454: (if (and (car (cdr (cdr state)))
455: (>= (car (cdr (cdr state))) 0))
456: (setq last-sexp (car (cdr (cdr state)))))
457: (if (or (nth 4 ostate))
458: (c-indent-line))
459: (if (or (nth 3 state))
460: (forward-line 1)
461: (setq innerloop-done t)))
462: (if (<= next-depth 0)
463: (setq outer-loop-done t))
464: (if outer-loop-done
465: nil
466: (if (/= last-depth next-depth)
467: (setq last-sexp nil))
468: (while (> last-depth next-depth)
469: (setq indent-stack (cdr indent-stack)
470: contain-stack (cdr contain-stack)
471: last-depth (1- last-depth)))
472: (while (< last-depth next-depth)
473: (setq indent-stack (cons nil indent-stack)
474: contain-stack (cons nil contain-stack)
475: last-depth (1+ last-depth)))
476: (if (null (car contain-stack))
477: (setcar contain-stack (or (car (cdr state))
478: (save-excursion (forward-sexp -1)
479: (point)))))
480: (forward-line 1)
481: (skip-chars-forward " \t")
482: (if (eolp)
483: nil
484: (if (and (car indent-stack)
485: (>= (car indent-stack) 0))
486: ;; Line is on an existing nesting level.
487: ;; Lines inside parens are handled specially.
488: (if (/= (char-after (car contain-stack)) ?{)
489: (setq this-indent (car indent-stack))
490: ;; Line is at statement level.
491: ;; Is it a new statement? Is it an else?
492: ;; Find last non-comment character before this line
493: (save-excursion
494: (setq at-else (looking-at "else\\W"))
495: (c-backward-to-noncomment opoint)
496: (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?{)))
497: ;; Preceding line did not end in comma or semi;
498: ;; indent this line c-continued-statement-offset
499: ;; more than previous.
500: (progn
501: (c-backward-to-start-of-continued-exp (car contain-stack))
502: (setq this-indent
503: (+ c-continued-statement-offset (current-column))))
504: ;; Preceding line ended in comma or semi;
505: ;; use the standard indent for this level.
506: (if at-else
507: (progn (c-backward-to-start-of-if opoint)
508: (setq this-indent (current-indentation)))
509: (setq this-indent (car indent-stack))))))
510: ;; Just started a new nesting level.
511: ;; Compute the standard indent for this level.
512: (let ((val (calculate-c-indent
513: (if (car indent-stack)
514: (- (car indent-stack))))))
515: (setcar indent-stack
516: (setq this-indent val))))
517: ;; Adjust line indentation according to its contents
518: (if (or (looking-at "case[ \t]")
519: (and (looking-at "[A-Za-z]")
520: (save-excursion
521: (forward-sexp 1)
522: (looking-at ":"))))
523: (setq this-indent (max 1 (+ this-indent c-label-offset))))
524: (if (= (following-char) ?})
525: (setq this-indent (- this-indent c-indent-level)))
526: (if (= (following-char) ?{)
527: (setq this-indent (+ this-indent c-brace-offset)))
528: ;; Put chosen indentation into effect.
529: (or (= (current-column) this-indent)
530: (= (following-char) ?\#)
531: (progn
532: (delete-region (point) (progn (beginning-of-line) (point)))
533: (indent-to this-indent)))
534: ;; Indent any comment following the text.
535: (or (looking-at comment-start-skip)
536: (if (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t)
537: (progn (indent-for-comment) (beginning-of-line)))))))))
538: ; (message "Indenting C expression...done")
539: )
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.