[gnu.emacs] Looking for c-style.el

mdb@silvlis.com (Mark D. Baushke) (11/17/88)

>  Date: Wed, 16 Nov 88 12:00:37 EST
>  From: sun!eddie.mit.edu!think!compass!worley (Dale Worley)
>  To: info-gnu-emacs@eddie.mit.edu
>  
>  Who archives c-style.el?  I've lost the message discussing it.

The original c-style.el was written by Daniel LaLiberte
<liberte@a.cs.uiuc.edu>.

I have included the version we are using here at Silvar-Lisco (some
additions were made by Lynn Slater <lrs@esl.com> while he worked
here and I don't have a copy of the original anymore...although I
believe the original ends before the commend about Lynn Slater's
additions).

Enjoy!
------------------------------------------------------------------------------
Mark D. Baushke                 Internet:    mdb%silvlis.com@sun.com
Silvar-Lisco, Inc.              Nameservers: mdb@silvlis.com
1080 Marsh Road                 Usenet:      {pyramid,sun}!silvlis!mdb
Menlo Park, CA 94025-1053       Telephone:   +1 415 853-6411 / +1 415 969-8328

;;------------------------- start c-style.el -------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; c-style.el --- Enhancements to c-mode, also sets c-style control variables.
;; 
;; Author          : Daniel LaLiberte (liberte@a.cs.uiuc.edu)
;; Created On      : Wed Aug 12 08:00:20 1987
;; Last Modified By: Mark D. Baushke
;; Last Modified On: Fri Oct 21 18:40:16 1988
;; Update Count    : 18
;; Status          : ok to use
;;
;; Enhancements made by Lynn Slater <lrs@esl.com>.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;---
; Definitions for buffer specific c-mode indentation style.
; Written by Daniel LaLiberte (liberte@a.cs.uiuc.edu)
; while at Gould.  This is free.

; There are several ways to call set-c-style.
;
; 1. Set the c-style variable in the local variables list 
;    with "c-style: GNU" or whatever you like and
;    call set-c-style without argument in c-mode-hook.
;
; 2. Call set-c-style with style argument in c-mode-hook.
;    This will set the style for every c file the same.
;
; 3. Put "eval: (set-c-style 'GNU)" in the local variables list.
; 
; 4. Call set-c-style interactively.  It prompts for the style name.

; The default value of c-style is default-c-style.
; I put (autoload 'set-c-style "c-style.el" nil t) in my .emacs.

;;; $Header: $
;;;
;;; $Log: $
;;;

;; Predefined styles
(defvar c-style-alist '(
			(GNU (c-indent-level . 2)
			     (c-continued-statement-offset . 2)
			     (c-brace-offset . 0)
			     (c-argdecl-indent . 5)
			     (c-label-offset . -2))
			(BSD (c-indent-level . 8)
			     (c-continued-statement-offset . 8)
			     (c-brace-offset . -8)
			     (c-argdecl-indent . 8)
			     (c-label-offset . -8))
			(K&R (c-indent-level . 5)
			     (c-continued-statement-offset . 5)
			     (c-brace-offset . -5)
			     (c-argdecl-indent . 0)
			     (c-label-offset . -5))
			(C++ (c-indent-level . 4)
			     (c-continued-statement-offset . 4)
			     (c-brace-offset . -4)
			     (c-argdecl-indent . 4)
			     (c-label-offset . -4))
			))
   
(defvar default-c-style 'DEFAULT
  "*The default value of c-style")
(defvar c-style default-c-style
  "*The buffer specific c indentation style.")



(defun set-c-style (&optional style)
  "Set up the c-mode style variables from the c-style variable or if
  STYLE argument is given, use that.  It makes the c indentation style 
  variables buffer local."

  (interactive)

  (let ((c-styles (mapcar 'car c-style-alist)))
	
    (if (interactive-p)
	(setq style
	      (let ((style-string	; get style name with completion
		     (completing-read
		      (format "Set c mode indentation style to (default %s): "
			      default-c-style)
		      (vconcat c-styles)
		      (function (lambda (arg) (memq arg c-styles)))
		      )))
		(if (string-equal "" style-string)
		    default-c-style
		  (intern style-string))
		)))
    
    ;;(setq style (or style c-style))	; use c-style if style is nil
    (setq style (or style default-c-style))	; use c-style if style is nil
    
    (make-local-variable 'c-style)
    (if (memq style c-styles)
	(setq c-style style)
      (error (message "Undefined or Bad c style: %s" style))
      )
    (message "c-style: %s" c-style)
      
    ;; finally, set the indentation style variables making each one local
    (mapcar (function (lambda (c-style-pair)
			(make-local-variable (car c-style-pair))
			(set (car c-style-pair)
			     (cdr c-style-pair))))
	    (cdr (assq c-style c-style-alist)))
    c-style
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lynn Slater <lrs@esl.com> additions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setq c-style-alist (append
		     '((default (c-indent-level . 4)
				 (c-continued-statement-offset . 4)
				 (c-brace-offset . 0)
				 (c-argdecl-indent . 4)
				 (c-label-offset . -2)
				 (c-auto-newline . nil)
				 )
			(standard (c-indent-level . 4)
				  (c-continued-statement-offset . 4)
				  (c-brace-offset . 0)
				  (c-argdecl-indent . 4)
				  (c-label-offset . -2)
				  (c-auto-newline . t)
				  )
			) c-style-alist))

(setq default-c-style 'standard)

(setq c-mode-hook (append (if (listp c-mode-hook)
			      c-mode-hook (list c-mode-hook)) '(set-c-style)))
 
(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."
  ;;(message "indent within comment")
  (let (end star-start)
    (save-excursion
      (beginning-of-line)
      (skip-chars-forward " \t")
      ;; newline before a * is (was) a special case
      (setq star-start (= (following-char) ?\*))
      ;;(message "start = %s" star-start)
      (skip-chars-backward " \t\n")
      (setq end (point))
      (beginning-of-line)
      (skip-chars-forward " \t")
      (and (re-search-forward "/\\*[ \t]*" end t)
	   ;;star-start for special case newline
	   (goto-char (1+ (match-beginning 0))))
      (current-column))))


(defun c-indent-line ();; called by indent-line-fcn
  "Indent current line as C code.
   Return the amount the indentation changed by."
  ;; special lrs side effect; if in a block comment line,
  ;; insert a *<space> to keep a block comment
  ;;(message "c-indent-line")
  (let ((indent (calculate-c-indent nil))
	beg shift-amt
	(case-fold-search nil)
	(special-end-comment nil) ;; lrs
	(pos (- (point-max) (point))))
    (beginning-of-line)
    (setq beg (point))
    (cond ((eq indent nil);; line is in a string
	   (setq indent (current-indentation)))
	  ((eq indent t) ;; line is in a comment
	   (setq indent (calculate-c-indent-within-comment))
	   (if (not (save-excursion ;; else it will add * to existing comments
		 (beginning-of-line)
		 (re-search-forward "^[ \t]*\\*"
				    (save-excursion (end-of-line) (point))
				    t)))
	       (save-excursion;; lrs
		 (if (= (char-after (- (point) 2)) ?\*)
		     (progn
		       (setq special-end-comment t)
		       ))
		 (insert "* ")))
	   )
	  ((looking-at "[ \t]*#")
	   (setq indent 0))
	  (t
	   (skip-chars-forward " \t")
	   (if (listp indent) (setq indent (car indent)))
	   (cond ((or (looking-at "case\\b")
		      (and (looking-at "[A-Za-z]")
			   (save-excursion
			     (forward-sexp 1)
			     (looking-at ":"))))
		  (setq indent (max 1 (+ indent c-label-offset))))
		 ((and (looking-at "else\\b")
		       (not (looking-at "else\\s_")))
		  (setq indent (save-excursion
				 (c-backward-to-start-of-if)
				 (current-indentation))))
		 ((= (following-char) ?})
		  (setq indent (- indent c-indent-level)))
		 ((= (following-char) ?{)
		  (setq indent (+ indent c-brace-offset))))))
    (skip-chars-forward " \t")
    (setq shift-amt (- indent (current-column)))
    (if (zerop shift-amt)
	(if (> (- (point-max) pos) (point))
	    (goto-char (- (point-max) pos)))
      (delete-region beg (point))
      (indent-to indent)
      ;; If initial point was within line's indentation,
      ;; position after the indentation.  Else stay at same point in text.
      (if (> (- (point-max) pos) (point))
	  (goto-char (- (point-max) pos))))
    (if (and special-end-comment
	     ;; also the previous line must have ended in a non-terminated
	     ;; /*
	     (save-excursion
	       (forward-line -1)
	       (non-terminated-comment-start)))	       
	(save-excursion
	  ;;(update-display)
	  ;;(sit-for 3)
	  (insert "\n/")
	  (backward-char 1)
	  (c-indent-line)
	  (backward-char 1)
	  (delete-char 1)
	  ))
     shift-amt))

(defun non-terminated-comment-start ()
  "determines if a c comment starts but does not terminate
   in the current line"
  (save-excursion
    (end-of-line)
    (let ((eol (point)))
      (beginning-of-line)
      (if (re-search-forward "^.*/\\*" eol t)
	  (progn
	    (goto-char (match-end 0))
	    (not (re-search-forward "^.*\\*/" eol t)))))))

(defun indent-new-comment-line ()
  "Break line at point and indent, continuing comment if presently within one."
  (interactive "*")
  ;;(message "new-comment-line")
  (let (comcol comstart)
    (skip-chars-backward " \t")
    (insert ?\n)
    (delete-region (point)
		   (progn (skip-chars-forward " \t")
			  (point)))
    (save-excursion
      (if (and comment-start
	       (let ((opoint (point)))
		 (forward-line -1)
		 (re-search-forward comment-start-skip opoint t)))
	  (progn
	    (goto-char (match-beginning 0))
	    (setq comcol (current-column))
	    (setq comstart (buffer-substring (point) (match-end 0))))))
    (if comcol
	(let ((comment-column comcol)
	      (comment-start comstart)
	      (comment-end comment-end))
	  (and comment-end (not (equal comment-end ""))
	       (if (not comment-multi-line)
		   (progn
		     (forward-char -1)
		     (insert comment-end)
		     (forward-char 1))
		 (setq comment-column (+ comment-column (length comment-start))
		       comment-start "")))
	  (if (not (eolp))
	      (setq comment-end ""))
	  (insert ?\n)
	  (forward-char -1)
	  (indent-for-comment)
	  (delete-char 1))
      (if fill-prefix
	  (insert fill-prefix)
	(indent-according-to-mode)))))

;; I have trouble only on a line that starts with /* and has data on it
;; in auto fill mode only!

;; This is used by indent-for-comment by autofill
;; to decide how much to indent a comment in C code
;; based on its context.
(defun c-comment-indent ()
  ;;(message "c-comment-indent")
  ;;(sit-for 2)
  (if (looking-at "^/\\*")
      0					;Existing comment at bol stays there.
    (save-excursion
      (skip-chars-backward " \t")
      (max (1+ (current-column))	;Else indent at comment column
	   comment-column)))		; except leave at least one space.
  )

;;------------------------- end c-style.el -------------------------