]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/c-mode.el
(easy-menu-define-key): Fixed bug with BEFORE
[gnu-emacs] / lisp / progmodes / c-mode.el
index b0c962dcae13ae82ff9f14923077c490b57859ad..ab9cf8dc9920281cb92fa68750f0b1b9ae310694 100644 (file)
@@ -1,5 +1,6 @@
 ;;; c-mode.el --- C code editing commands for Emacs
-;; Copyright (C) 1985, 1986, 1987, 1992, 1994 Free Software Foundation, Inc.
+
+;; Copyright (C) 1985, 86, 87, 92, 94, 95 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: c
 ;; 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.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
 ;; A smart editing mode for C code.  It knows a lot about C syntax and tries
-;; to position the curser according to C layout conventions.  You can
+;; to position the cursor according to C layout conventions.  You can
 ;; change the details of the layout style with option variables.  Load it
 ;; and do M-x describe-mode for details.
 
 ;;; Code:
+(defgroup old-c nil
+  "Old C code editing commands for Emacs."
+  :prefix "c-"
+  :group 'languages)
+
 
 (defvar c-mode-abbrev-table nil
   "Abbrev table in use in C mode.")
 
 (define-key c-mode-map [menu-bar] (make-sparse-keymap))
 
+;; "C-mode" is not strictly the right punctuation--it should be "C
+;; mode"--but that would look like two menu items.  "C-mode" is the
+;; best alternative I can think of.
 (define-key c-mode-map [menu-bar c]
-  (cons "C Mode" (make-sparse-keymap "C Mode")))
+  (cons "C-mode" (make-sparse-keymap "C-mode")))
 
 (define-key c-mode-map [menu-bar c comment-region]
   '("Comment Out Region" . comment-region))
 (define-key c-mode-map [menu-bar c forward-stmt]
   '("Forward Statement" . c-end-of-statement))
 
+(put 'comment-region 'menu-enable 'mark-active)
+(put 'c-macro-expand 'menu-enable 'mark-active)
+(put 'c-backslash-region 'menu-enable 'mark-active)
+
 (autoload 'c-macro-expand "cmacexp"
   "Display the result of expanding all C macros occurring in the region.
 The expansion is entirely correct because it uses the C preprocessor."
@@ -105,68 +119,187 @@ The expansion is entirely correct because it uses the C preprocessor."
   (modify-syntax-entry ?| "." c-mode-syntax-table)
   (modify-syntax-entry ?\' "\"" c-mode-syntax-table))
 
-(defconst c-indent-level 2
-  "*Indentation of C statements with respect to containing block.")
-(defconst c-brace-imaginary-offset 0
-  "*Imagined indentation of a C open brace that actually follows a statement.")
-(defconst c-brace-offset 0
-  "*Extra indentation for braces, compared with other text in same context.")
-(defconst c-argdecl-indent 5
-  "*Indentation level of declarations of C function arguments.")
-(defconst c-label-offset -2
-  "*Offset of C label lines and case statements relative to usual indentation.")
-(defconst c-continued-statement-offset 2
-  "*Extra indent for lines not starting new statements.")
-(defconst c-continued-brace-offset 0
+(defcustom c-indent-level 2
+  "*Indentation of C statements with respect to containing block."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-brace-imaginary-offset 0
+  "*Imagined indentation of a C open brace that actually follows a statement."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-brace-offset 0
+  "*Extra indentation for braces, compared with other text in same context."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-argdecl-indent 5
+  "*Indentation level of declarations of C function arguments."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-label-offset -2
+  "*Offset of C label lines and case statements relative to usual indentation."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-continued-statement-offset 2
+  "*Extra indent for lines not starting new statements."
+  :type 'integer
+  :group 'old-c)
+(defcustom c-continued-brace-offset 0
   "*Extra indent for substatements that start with open-braces.
-This is in addition to `c-continued-statement-offset'.")
+This is in addition to `c-continued-statement-offset'."
+  :type 'integer
+  :group 'old-c)
 (defconst c-style-alist
   '(("GNU"
      (c-indent-level               .  2)
      (c-argdecl-indent             .  5)
      (c-brace-offset               .  0)
+     (c-continued-brace-offset     .  0)
      (c-label-offset               . -2)
      (c-continued-statement-offset .  2))
     ("K&R"
      (c-indent-level               .  5)
      (c-argdecl-indent             .  0)
-     (c-brace-offset               . -5)
+     (c-brace-offset               .  0)
+     (c-continued-brace-offset     . -5)
      (c-label-offset               . -5)
      (c-continued-statement-offset .  5))
     ("BSD"
      (c-indent-level               .  4)
      (c-argdecl-indent             .  4)
+     (c-brace-offset               .  0)
      (c-continued-brace-offset     . -4)
      (c-label-offset               . -4)
      (c-continued-statement-offset .  4))
     ("C++"
-     (c-indent-level               . 4)
-     (c-continued-statement-offset . 4)
-     (c-brace-offset               . -4)
-     (c-argdecl-indent             . 0)
+     (c-indent-level               .  4)
+     (c-argdecl-indent             .  0)
+     (c-brace-offset               .  0)
+     (c-continued-brace-offset     . -4)
      (c-label-offset               . -4)
-     (c-auto-newline               . t))
+     (c-continued-statement-offset .  4)
+     (c-auto-newline               .  t))
     ("Whitesmith"
      (c-indent-level               .  4)
      (c-argdecl-indent             .  4)
      (c-brace-offset               .  0)
+     (c-continued-brace-offset     .  0)
      (c-label-offset               . -4)
      (c-continued-statement-offset .  4))))
 
-(defconst c-auto-newline nil
+(defcustom c-auto-newline nil
   "*Non-nil means automatically newline before and after braces,
 and after colons and semicolons, inserted in C code.
 If you do not want a leading newline before braces then use:
-  (define-key c-mode-map \"{\" 'electric-c-semi)")
+  (define-key c-mode-map \"{\" 'electric-c-semi)"
+  :type 'boolean
+  :group 'old-c)
 
-(defconst c-tab-always-indent t
+(defcustom c-tab-always-indent t
   "*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.")
+regardless of where in the line point is when the TAB command is used."
+  :type 'boolean
+  :group 'old-c)
 
 ;;; Regular expression used internally to recognize labels in switch
 ;;; statements.
 (defconst c-switch-label-regexp "case[ \t'/(]\\|default[ \t]*:")
 
+;; This is actually the expression for C++ mode, but it's used for C too.
+(defvar c-imenu-generic-expression
+  (`
+   ((nil
+     (,
+      (concat
+       "^"                               ; beginning of line is required
+       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; type specs; there can be no
+       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"     ; more than 3 tokens, right?
+
+       "\\("                             ; last type spec including */&
+       "[a-zA-Z0-9_:]+"
+       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"        ; either pointer/ref sign or whitespace
+       "\\)?"                            ; if there is a last type spec
+       "\\("                         ; name; take that into the imenu entry
+       "[a-zA-Z0-9_:~]+"                     ; member function, ctor or dtor...
+                                       ; (may not contain * because then
+                                       ; "a::operator char*" would become "char*"!)
+       "\\|"
+       "\\([a-zA-Z0-9_:~]*::\\)?operator"
+       "[^a-zA-Z1-9_][^(]*"          ; ...or operator
+       " \\)"
+       "[ \t]*([^)]*)[ \t\n]*[^              ;]" ; require something other than a ; after
+                                       ; the (...) to avoid prototypes.  Can't
+                                       ; catch cases with () inside the parentheses
+                                       ; surrounding the parameters
+                                       ; (like "int foo(int a=bar()) {...}"
+
+       )) 6)
+    ("Class"
+     (, (concat
+        "^"                               ; beginning of line is required
+        "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+        "class[ \t]+"
+        "\\([a-zA-Z0-9_]+\\)"                ; this is the string we want to get
+        "[ \t]*[:{]"
+        )) 2)
+;; Example of generic expression for finding prototypes, structs, unions, enums.
+;; Uncomment if you want to find these too.  It will be a bit slower gathering
+;; the indexes.
+;    ("Prototypes"
+;     (,
+;      (concat
+;       "^"                              ; beginning of line is required
+;       "\\(template[ \t]*<[^>]+>[ \t]*\\)?" ; there may be a "template <...>"
+;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; type specs; there can be no
+;       "\\([a-zA-Z0-9_:]+[ \t]+\\)?"    ; more than 3 tokens, right?
+
+;       "\\("                            ; last type spec including */&
+;       "[a-zA-Z0-9_:]+"
+;       "\\([ \t]*[*&]+[ \t]*\\|[ \t]+\\)"       ; either pointer/ref sign or whitespace
+;       "\\)?"                           ; if there is a last type spec
+;       "\\("                        ; name; take that into the imenu entry
+;       "[a-zA-Z0-9_:~]+"                    ; member function, ctor or dtor...
+;                                      ; (may not contain * because then
+;                                      ; "a::operator char*" would become "char*"!)
+;       "\\|"
+;       "\\([a-zA-Z0-9_:~]*::\\)?operator"
+;       "[^a-zA-Z1-9_][^(]*"         ; ...or operator
+;       " \\)"
+;       "[ \t]*([^)]*)[ \t\n]*;"       ; require ';' after
+;                                      ; the (...) Can't
+;                                      ; catch cases with () inside the parentheses
+;                                      ; surrounding the parameters
+;                                      ; (like "int foo(int a=bar());"
+;       )) 6)
+;    ("Struct"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "struct[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+;    ("Enum"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "enum[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+;    ("Union"
+;     (, (concat
+;       "^"                            ; beginning of line is required
+;       "\\(static[ \t]+\\)?"          ; there may be static or const.
+;       "\\(const[ \t]+\\)?"
+;       "union[ \t]+"
+;       "\\([a-zA-Z0-9_]+\\)"          ; this is the string we want to get
+;       "[ \t]*[{]"
+;       )) 3)
+    ))
+  "Imenu generic expression for C mode.  See `imenu-generic-expression'.")
 \f
 (defun c-mode ()
   "Major mode for editing C code.
@@ -251,6 +384,9 @@ if that value is non-nil."
   (setq comment-multi-line t)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq 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))
 
 (defun c-outline-level ()
@@ -308,7 +444,7 @@ preserving the comment indentation or line-starting decorations."
              (paragraph-start
               ;; Lines containing just a comment start or just an end
               ;; should not be filled into paragraphs they are next to.
-              (concat 
+              (concat
                paragraph-start
                "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
              (paragraph-separate
@@ -419,7 +555,7 @@ preserving the comment indentation or line-starting decorations."
                (paragraph-start
                 ;; Lines containing just a comment start or just an end
                 ;; should not be filled into paragraphs they are next to.
-                (concat 
+                (concat
                  paragraph-start
                  "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
                (paragraph-separate
@@ -437,8 +573,8 @@ preserving the comment indentation or line-starting decorations."
                                  (if comment-start-place
                                      (goto-char comment-start-place)
                                    (search-backward "/*"))
-                                 ;; Protect text before the comment start 
-                                 ;; by excluding it.  Add spaces to bring back 
+                                 ;; Protect text before the comment start
+                                 ;; by excluding it.  Add spaces to bring back
                                  ;; proper indentation of that point.
                                  (let ((column (current-column)))
                                    (prog1 (point)
@@ -450,15 +586,16 @@ preserving the comment indentation or line-starting decorations."
                                  (search-forward "*/" nil 'move)
                                  (forward-line 1)
                                  (point)))
-             (goto-char (point-max))
-             (forward-line -1)
-             ;; And comment terminator was on a separate line before,
-             ;; keep it that way.
-             ;; This also avoids another problem:
-             ;; if the fill-prefix ends in a *, it could eat up
-             ;; the * of the comment terminator.
-             (if (looking-at "[ \t]*\\*/")
-                 (narrow-to-region (point-min) (point)))
+             (save-excursion
+               (goto-char (point-max))
+               (forward-line -1)
+               ;; And comment terminator was on a separate line before,
+               ;; keep it that way.
+               ;; This also avoids another problem:
+               ;; if the fill-prefix ends in a *, it could eat up
+               ;; the * of the comment terminator.
+               (if (looking-at "[ \t]*\\*/")
+                   (narrow-to-region (point-min) (point))))
              (fill-paragraph arg)
              (save-excursion
                ;; Delete the chars we inserted to avoid clobbering
@@ -858,7 +995,7 @@ Returns nil if line starts inside a string, t if in a comment."
                     ;; The first following code counts
                     ;; if it is before the line we want to indent.
                     (and (< (point) indent-point)
-                         (- 
+                         (-
                           (if (> colon-line-end (point))
                               (- (current-indentation) c-label-offset)
                             (current-column))
@@ -869,27 +1006,32 @@ Returns nil if line starts inside a string, t if in a comment."
                           (if (= (following-char) ?\{) c-brace-offset 0)))))
                 ;; If no previous statement,
                 ;; indent it relative to line brace is on.
-                ;; For open brace in column zero, don't let statement
-                ;; start there too.  If c-indent-level 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))))))))))
+                (calculate-c-indent-after-brace))))))))
+
+(defun calculate-c-indent-after-brace ()
+  "Return the proper C indent for the first line after an open-brace.
+This function is called with point before the brace."
+  ;; For open brace in column zero, don't let statement
+  ;; start there too.  If c-indent-level 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))))
 
 (defun calculate-c-indent-within-comment (&optional after-star)
   "Return the indentation amount for line inside a block comment.
@@ -1056,7 +1198,7 @@ If within a string or comment, move by sentences instead of statements."
                          (not (re-search-forward "[;{}]" end t)))))))
        (re-search-backward "[;}]")
        (forward-char 1))
-    (error 
+    (error
      (let ((beg (point)))
        (backward-up-list -1)
        (let ((end (point)))
@@ -1207,7 +1349,7 @@ If within a string or comment, move by sentences instead of statements."
                (if (= (char-after (car contain-stack)) ?{)
                    (save-excursion
                      (goto-char (car contain-stack))
-                     (setq val (+ c-indent-level (current-column))))
+                     (setq val (calculate-c-indent-after-brace)))
                  (setq val (calculate-c-indent
                             (if (car indent-stack)
                                 (- (car indent-stack))
@@ -1385,15 +1527,17 @@ Available styles are GNU, K&R, BSD and Whitesmith."
 \f
 ;;; This page handles insertion and removal of backslashes for C macros.
 
-(defvar c-backslash-column 48
-  "*Minimum column for end-of-line backslashes of macro definitions.")
+(defcustom c-backslash-column 48
+  "*Minimum column for end-of-line backslashes of macro definitions."
+  :type 'integer
+  :group 'old-c)
 
 (defun c-backslash-region (from to delete-flag)
   "Insert, align, or delete end-of-line backslashes on the lines in the region.
 With no argument, inserts backslashes and aligns existing backslashes.
 With an argument, deletes the backslashes.
 
-This function does not modify the last line of the region if the region ends 
+This function does not modify the last line of the region if the region ends
 right at the start of the following line; it does not modify blank lines
 at the start of the region.  So you can put the region around an entire macro
 definition and conveniently use this command."
@@ -1526,5 +1670,7 @@ move backward across a preprocessor conditional."
        (setq count (+ count increment))))
     (push-mark)
     (goto-char new)))
+\f
+(provide 'c-mode)
 
 ;;; c-mode.el ends here