Article View: comp.emacs
Article #7950Re: Good c-mode for GNU?
From: Mark Davies
Date: Wed, 23 Nov 1988 03:51
Date: Wed, 23 Nov 1988 03:51
392 lines
13897 bytes
13897 bytes
In article <591@husc6.harvard.edu> kovar@husc4.harvard.edu (David Kovar) writes:
> I used to use UniPress emacs and was quite happy with the electric-c
>modes available for it. They'd provide brace completions, for statement
>outlines, and the like. The GNU Emacs c-mode is woefully inadaquate
>in my eyes. Has anyone written a more intelligent version?
>
>-David Kovar
This is a mode that started off many years ago looking a lot like Gosmacs
elec-c mode. It has evolved (devolved?) a lot since then. There is one
major philosophical difference with the gosmacs version. I don't like
going into recursive-edit to insert parts of a template (eg the expression
in a case stmt) as I am prone to wonder off and edit something else and
then notice half an hour later that I am still in recursive edit.
I've been meaning to post this for a long time, but wanted to make a few
more additions to it. I still want to make those additions but haven't in
the last year and probably won't for a while, so here it is.
This version definitely works on 18.51 and 18.52 (and I think worked
unchanged on 18.49)
cheers
mark
--------------------cut here--------------------------
;; elec C code editing commands for Emacs
;; Mark Davies <mark@comp.vuw.ac.nz> - Dec 1985, revised Jun 1987
;; (C) Copyright 1987 Mark Davies
;; This file is released under the terms of the GNU Emacs General Public
;; Licence.
;; I invoke this from my .emacs file with the following incantation
;; (defvar c-mode-hook 'elec-c-mode)
;; (defvar elec-c-mode-hook '(lambda () (auto-fill-mode 1)))
;; (setq c-auto-newline t)
;; Things to do:
;; o allow option to put open braces on separate line. ie. formatting ala
;; Stallman.
;; o place the statement on current line in condition of a new if/while/do
;; construct.
;; o Add Comments
(defvar elec-c-mode-abbrev-table nil
"Abbrev table in use in elec-C-mode buffers.")
(defvar elec-c-mode-map nil
"Keymap used in elec C mode.")
(defvar elec-c-verbatim nil
"Should abbrevs be expanded explicitly?")
(setq elec-c-mode-map (make-sparse-keymap))
(define-key elec-c-mode-map "{" 'elec-c-left-brace)
(define-key elec-c-mode-map "}" 'electric-c-brace)
(define-key elec-c-mode-map "(" 'elec-c-opening-brac)
(define-key elec-c-mode-map "[" 'elec-c-opening-brac)
(define-key elec-c-mode-map ";" 'elec-c-semi)
(define-key elec-c-mode-map ":" 'electric-c-terminator)
(define-key elec-c-mode-map "\e\C-h" 'mark-c-function)
(define-key elec-c-mode-map "\e\C-q" 'indent-c-exp)
(define-key elec-c-mode-map "\177" 'backward-delete-char-untabify)
(define-key elec-c-mode-map "\C-c\C-c" 'elec-c-close-block)
(define-key elec-c-mode-map "\C-cv" 'toggle-verbatim)
(define-key elec-c-mode-map "\e{" 'elec-c-remove-braces)
(define-key elec-c-mode-map "\C-j" 'elec-c-linefeed)
(define-key elec-c-mode-map "\t" 'c-indent-command)
(modify-syntax-entry ?# "w" c-mode-syntax-table)
(modify-syntax-entry ?_ "w" c-mode-syntax-table)
(defconst comment-edged nil
"*Use comments of the form:
/*
* ...
*/")
(defun elec-c-mode ()
"High powered C editing mode
Elec C mode provides expansion of the C control constructs:
if, else, while, for, do, and switch.
The user types the keyword immediately followed by a space, which causes
the construct to be expanded, and the user positioned where (s)he is most
likely to want to be.
eg. when the user types a space following \"if\" the following appears in
the buffer:
if () {
}
and the cursor is between the parentheses. The user can then type some
boolean expression within the parens. Having done that, typing \\[elec-c-linefeed]
places you, appropriately indented on a new line between the braces.
Various characters in C almost always come in pairs: {}, (), [].
When the user types the first, he gets the second as well, with optional
special formatting done on {}. You can always quote (with \\[quoted-insert]) the left
\"paren\" to avoid the expansion.
#de, and #in are defined as abbreviations for #define and #include
respectively.
With auto-fill-mode on, three types of automatic formatting of comments are
possible. The default is of the form
/* ... ... */
/* ... ... */
If comment-multi-line is set non-nil you get comments of the form
/* ... ...
... ... */
If additionally comment-edged is set non-nil you get comments of the form
/*
* ... ...
*/
Expression and list commands understand all C brackets.
Tab indents for C code.
Paragraphs are separated by blank lines only.
Delete converts tabs to spaces as it moves back.
\\{elec-c-mode-map}
Variables controlling indentation style:
c-auto-newline
Non-nil means automatically newline before and after braces,
and after colons and semicolons, inserted in C code.
with this on colons and semicolons want to go to the end of the line.
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-brace-offset
Extra indentation for a 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.
Turning on elec C mode calls the value of the variable elec-c-mode-hook
with no args, if that value is non-nil."
(interactive)
(kill-all-local-variables)
(use-local-map elec-c-mode-map)
(setq major-mode 'elec-c-mode)
(setq mode-name "elec C")
(if (not elec-c-mode-abbrev-table)
(let ((prev-a-c abbrevs-changed))
(define-abbrev-table 'elec-c-mode-abbrev-table '(
("main" "main" elec-main 0)
("argc" "argc" elec-argc 0)
("if" "if" elec-if-while 0)
("switch" "switch" elec-if-while 0)
("while" "while" elec-if-while 0)
("else" "else" elec-else 0)
("for" "for" elec-for 0)
("do" "do" elec-do 0)
("#d" "#define" nil 0)
("#de" "#define" nil 0)
("#e" "#endif" nil 0)
("#i" "#ifdef" nil 0)
("#in" "#include" nil 0)))
(setq abbrevs-changed prev-a-c)))
(setq local-abbrev-table elec-c-mode-abbrev-table)
(abbrev-mode 1)
(set-syntax-table c-mode-syntax-table)
(make-local-variable 'elec-c-verbatim)
(make-local-variable 'paragraph-start)
(setq paragraph-start (concat "^$\\|" page-delimiter))
(make-local-variable 'paragraph-separate)
(setq paragraph-separate paragraph-start)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'c-indent-line)
(make-local-variable 'require-final-newline)
(setq require-final-newline t)
(make-local-variable 'comment-start)
(setq comment-start "/* ")
(make-local-variable 'comment-end)
(setq comment-end " */")
(make-local-variable 'comment-column)
(setq comment-column 32)
(make-local-variable 'comment-start-skip)
(setq comment-start-skip "/\\*+ *")
(make-local-variable 'comment-indent-hook)
(setq comment-indent-hook 'c-comment-indent)
(make-local-variable 'parse-sexp-ignore-comments)
(setq parse-sexp-ignore-comments t)
(run-hooks 'elec-c-mode-hook))
; so lets hope noone writes *LARGE* C files.
(defun elec-c-inside-comment-p ()
(nth 4 (parse-partial-sexp (point-min) (point))))
(defun elec-c-inside-string-p ()
(nth 3 (parse-partial-sexp (point-min) (point))))
(defun elec-c-inside-comment-or-string-p ()
(let ((parse-state (parse-partial-sexp (point-min) (point))))
(or (nth 4 parse-state) (nth 3 parse-state))))
(defun elec-c-open-block ()
(interactive)
(search-forward "{")
(backward-char 1)
(forward-sexp 1)
(backward-char 1)
(split-line)
(c-indent-line))
(defun elec-c-close-block ()
(interactive)
(while (not (looking-at "{"))
(backward-up-list 1))
(forward-sexp 1)
(save-excursion
(next-line -1)
(delete-blank-lines)
(beginning-of-line)
(if (looking-at "[ \t]*$")
(kill-line 1)))
(end-of-line)
(newline)
(c-indent-line))
(defun elec-c-remove-braces ()
"remove the surrounding pair of {}'s from the function."
(interactive)
(save-excursion
(while (not (looking-at "{"))
(backward-up-list 1))
(let (end)
(save-excursion ; kill tail
(forward-sexp 1)
(delete-char -1)
(delete-horizontal-space)
(and (bolp) (eolp)
(delete-char 1))
(setq end (point-marker)))
(delete-char 1) ; kill head
(delete-horizontal-space)
(and (bolp) (eolp)
(delete-char 1))
(while (<= (point) (marker-position end))
(c-indent-line)
(forward-line 1)))))
(defun elec-c-linefeed ()
"Go to end of line, open a new line and indent appropriately."
(interactive)
(end-of-line)
(newline-and-indent))
(defun elec-c-semi (arg)
"Insert character and correct line's indentation."
(interactive "P")
(if c-auto-newline
(let ((end (point)))
(if (not (save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(or (= (following-char) ?#)
(progn
(beginning-of-defun)
(let ((pps (parse-partial-sexp (point) end)))
(or (nth 3 pps) (nth 4 pps) (nth 5 pps)))))))
(end-of-line))
(electric-c-terminator arg))
(self-insert-command (prefix-numeric-value arg))))
(defun elec-c-left-brace ()
"if c-auto-newline is on insert matching close brace and format appropriately."
(interactive)
(if (or (not c-auto-newline)
(c-inside-parens-p)
(elec-c-inside-comment-or-string-p))
(insert ?{)
(end-of-line)
(delete-horizontal-space)
(if (/= (char-syntax (preceding-char)) ? )
(insert ? ))
(insert ?{)
(c-indent-line)
(insert "\n\n}"))
(c-indent-line)
(next-line -1)
(c-indent-line))
(defun elec-c-opening-brac ()
"For one of (, [ insert it and its pair, and postion point in the centre"
(interactive)
(insert last-command-char)
(if (not (elec-c-inside-comment-or-string-p))
(save-excursion
(cond
((= last-command-char ?\() (insert ?\)))
((= last-command-char ?[) (insert ?]))))))
(defun elec-main ()
(if (elec-c-inside-comment-or-string-p)
nil
(insert-string " ()\n{\n}\n")
(search-backward ")")
(setq unread-command-char ?\^?)))
(defun elec-argc ()
(if (save-excursion
(beginning-of-line)
(looking-at "[ \t]*main[ \t](argc"))
(progn
(insert-string ", argv")
(end-of-line)
(newline) (c-indent-line)
(insert-string "int argc;")
(newline) (c-indent-line)
(insert-string "char *argv [];")
(elec-c-open-block)
(setq unread-command-char ?\^?))))
(defun elec-if-while ()
(if (elec-c-inside-comment-or-string-p)
nil
(insert-string " () {\n}")
(c-indent-line)
(search-backward ")")
(setq unread-command-char ?\^?)))
(defun elec-else ()
(if (elec-c-inside-comment-or-string-p)
nil
(insert-string " {\n\n}")
(c-indent-line)
(next-line -1)
(c-indent-line)
(setq unread-command-char ?\^?)))
(defun elec-for ()
(if (elec-c-inside-comment-or-string-p)
nil
(insert-string " (;;) {\n}")
(c-indent-line)
(search-backward ";;)")
(setq unread-command-char ?\^?)))
(defun elec-do ()
(if (elec-c-inside-comment-or-string-p)
nil
(insert-string " {\n\n} while ();")
(c-indent-line)
(next-line -1)
(c-indent-line)
(setq unread-command-char ?\^?)))
; this is a HACK but I can't think of a better place to do it.
(defun calculate-c-indent-within-comment ()
"Return the indentation amount for line, assuming that
the current line is to be regarded as part of a block comment."
(let (end star-start)
(and (eq major-mode 'elec-c-mode)
comment-edged
(/= last-command-char ?\t)
(save-excursion
(insert "* ")))
(save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(setq star-start (= (following-char) ?\*))
(skip-chars-backward " \t\n")
(setq end (point))
(beginning-of-line)
(skip-chars-forward " \t")
(and (re-search-forward "/\\*[ \t]*" end t)
star-start
(goto-char (1+ (match-beginning 0))))
(current-column))))
(defun toggle-verbatim (arg)
"Toggle elec-c verbatim mode.
Doesn't expand keywords unless explicitly
This command toggles that mode (off->on, on->off),
with an argument, turns it on iff arg is positive, otherwise off."
(interactive "P")
(abbrev-mode arg)
(or (assq 'elec-c-verbatim minor-mode-alist)
(setq minor-mode-alist (append minor-mode-alist
(list '(elec-c-verbatim
" Verbatim")))))
(setq elec-c-verbatim
(if (null arg) (not elec-c-verbatim)
(> (prefix-numeric-value arg) 0))))
--
Domainised: mark@comp.vuw.ac.nz Bang form: ...!uunet!vuwcomp!mark
Technical Details
Message-ID:
<14399@comp.vuw.ac.nz>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!munnari!vuwcomp!markReferences:
<279@ge1cbx.UUCP> <591@husc6.harvard.edu>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!munnari!vuwcomp!mark From: mark@comp.vuw.ac.nz (Mark Davies) Newsgroups: comp.emacs Subject: Re: Good c-mode for GNU? Keywords: GNU Message-ID: <14399@comp.vuw.ac.nz> Date: 23 Nov 88 03:51:09 GMT References: <279@ge1cbx.UUCP> <591@husc6.harvard.edu> Reply-To: mark@comp.vuw.ac.nz (Mark Davies) Organization: Dept. of Comp. Sci., Victoria Uni. of Wellington, New Zealand. Lines: 392