kovar@husc4.HARVARD.EDU (11/14/88)
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
mark@comp.vuw.ac.nz (Mark Davies) (11/23/88)
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