270 lines
8.6 KiB
EmacsLisp
270 lines
8.6 KiB
EmacsLisp
;;; C comment mode - An auto-filled comment mode for gnu c-mode.
|
|
;;;
|
|
;;; Author: Robert Mecklenburg
|
|
;;; Computer Science Dept.
|
|
;;; University of Utah
|
|
;;; From: mecklen@utah-gr.UUCP (Robert Mecklenburg)
|
|
;;; Also hartzell@Boulder.Colorado.EDU
|
|
;;; (c) 1986, University of Utah
|
|
;;;
|
|
;;; Everyone is granted permission to copy, modify and redistribute
|
|
;;; this file, provided the people they give it to can.
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; I have written a "global comment" minor-mode which performs auto-fill,
|
|
;;; fill-paragraph, and auto-indentation functions. This function only
|
|
;;; works for comments which occupy an entire line (not comments to the
|
|
;;; right of code). The mode has several options set through variables.
|
|
;;; If the variable c-comment-starting-blank is non-nil multi-line
|
|
;;; comments come out like this:
|
|
;;;
|
|
;;; /*
|
|
;;; * Your favorite
|
|
;;; * multi-line comment.
|
|
;;; */
|
|
;;;
|
|
;;; otherwise they look like this:
|
|
;;;
|
|
;;; /* Your Favorite
|
|
;;; * multi-line comment.
|
|
;;; */
|
|
;;;
|
|
;;; If the variable c-comment-hanging-indent is non-nil K&R style comments
|
|
;;; are indented automatically like this:
|
|
;;;
|
|
;;; /* my_func - For multi-line comments with hanging indent
|
|
;;; * the text is lined up after the dash.
|
|
;;; */
|
|
;;;
|
|
;;; otherwise the text "the text" (!) is lined up under my_func. If a
|
|
;;; comment fits (as typed) on a single line it remains a single line
|
|
;;; comment even if c-comment-starting-blank is set. If
|
|
;;; c-comment-indenting is non-nil hitting carriage return resets the
|
|
;;; indentation for the next line to the current line's indentation
|
|
;;; (within the comment) like this:
|
|
;;;
|
|
;;; /* Typing along merrily....
|
|
;;; * Now I indent with spaces, when I hit return
|
|
;;; * the indentation is automatically set to
|
|
;;; * ^ here.
|
|
;;; */
|
|
;;;
|
|
;;; Due to my lack of understanding of keymaps this permanently resets M-q
|
|
;;; to my own fill function. I would like to have the comment mode
|
|
;;; bindings only in comment mode but I can't seem to get that to work.
|
|
;;; If some gnu guru can clue me in, I'd appreciate it.
|
|
;;;
|
|
(defvar c-comment-starting-blank t
|
|
"*Controls whether global comments have an initial blank line.")
|
|
(defvar c-comment-indenting t
|
|
"*If set global comments are indented to the level of the previous line.")
|
|
(defvar c-comment-hanging-indent t
|
|
"*If true, comments will be automatically indented to the dash.")
|
|
(defvar c-hang-already-done t
|
|
"If true we have performed the haning indent already for this comment.")
|
|
|
|
|
|
;;;
|
|
;;; c-comment-map - This is a sparse keymap for comment mode which
|
|
;;; gets inserted when c-comment is called.
|
|
;;;
|
|
(defvar c-comment-mode-map ()
|
|
"Keymap used in C comment mode.")
|
|
(if c-comment-mode-map
|
|
()
|
|
(setq c-comment-mode-map (copy-keymap c-mode-map))
|
|
(define-key c-comment-mode-map "\e\r" 'newline)
|
|
(define-key c-comment-mode-map "\eq" 'set-fill-and-fill)
|
|
(define-key c-comment-mode-map "\r" 'set-fill-and-return))
|
|
|
|
;;;
|
|
;;; c-comment - This is a filled comment mode which can format
|
|
;;; indented text, do hanging indents, and symetric
|
|
;;; placement of comment delimiters.
|
|
;;;
|
|
(defun c-comment ()
|
|
"Edit a C comment with filling and indentation.
|
|
This performs hanging indentation, symmetric placement of delimiters,
|
|
and Indented-Text mode style indentation. Type 'M-x apropos
|
|
c-comment' for information on options."
|
|
(interactive)
|
|
(let
|
|
;; Save old state.
|
|
((auto-fill-hook (if c-comment-indenting
|
|
'do-indented-auto-fill 'do-auto-fill))
|
|
; (comment-start nil)
|
|
(comment-multi-line t)
|
|
(comment-start-skip "/*\\*+[ ]*")
|
|
(paragraph-start-ref paragraph-start)
|
|
fill-prefix paragraph-start paragraph-separate opoint)
|
|
|
|
;; Determine if we are inside a comment.
|
|
(setq in-comment
|
|
(save-excursion
|
|
(and (re-search-backward "/\\*\\|\\*/" 0 t)
|
|
(string= "/*" (buffer-substring (point) (+ (point) 2))))))
|
|
|
|
;; Indent the comment and set the fill prefix to comment continuation
|
|
;; string. If we are already in a comment get the indentation on
|
|
;; the current line.
|
|
(setq c-hang-already-done nil)
|
|
|
|
;; Set the beginning of the comment and insert the blank line if needed.
|
|
(use-local-map c-comment-mode-map)
|
|
(if (not in-comment)
|
|
(progn (c-indent-line)
|
|
(insert "/* ")
|
|
(setq fill-prefix (get-current-fill (point)))
|
|
(recursive-edit)
|
|
|
|
;; If the comment fits on one line, place the close
|
|
;; comment at the end of the line. Otherwise, newline.
|
|
(setq opoint (point))
|
|
(if (and (save-excursion (beginning-of-line)
|
|
(search-forward "/*" opoint t))
|
|
(<= (+ (current-column) 3) 79))
|
|
(insert " */")
|
|
(insert "\n*/"))
|
|
|
|
(c-indent-line))
|
|
(progn (setq fill-prefix (get-current-fill (point)))
|
|
(recursive-edit)
|
|
(search-forward "*/" (buffer-size) t)
|
|
(forward-line 1)))
|
|
|
|
;; If starting blank enabled, insert a newline, etc., but only if
|
|
;; this comment requires multiple lines.
|
|
(if c-comment-starting-blank
|
|
(save-excursion
|
|
(setq opoint (point))
|
|
(forward-line -1)
|
|
(if (or (null (search-forward "/*" opoint t))
|
|
(null (search-forward "*/" opoint t)))
|
|
(progn
|
|
(search-backward "/*")
|
|
(re-search-forward comment-start-skip opoint t)
|
|
(setq fill-prefix (get-current-fill (point)))
|
|
(if (not (looking-at "\n"))
|
|
(insert ?\n fill-prefix))))))
|
|
; (indent-new-comment-line))))))
|
|
|
|
;; Move cursor to indentation.
|
|
(c-indent-line)
|
|
(use-local-map c-mode-map)
|
|
)
|
|
)
|
|
|
|
|
|
;;;
|
|
;;; set-fill-and-fill - Get the current fill for this line and fill
|
|
;;; the paragraph.
|
|
;;;
|
|
(defun set-fill-and-fill (arg)
|
|
"Get the fill-prefix and fill the current paragraph."
|
|
|
|
(interactive "P")
|
|
(setq fill-prefix (get-current-fill (point)))
|
|
(fill-paragraph arg))
|
|
|
|
;;;
|
|
;;; set-fill-and-return - Set the current fill prefix and
|
|
;;; indent-new-comment-line.
|
|
;;;
|
|
(defun set-fill-and-return ()
|
|
"Set the current fill prefix and move to the next line."
|
|
|
|
(interactive)
|
|
(if c-comment-indenting
|
|
(setq fill-prefix (get-current-fill (point))))
|
|
(insert ?\n fill-prefix))
|
|
|
|
;;;
|
|
;;; do-indented-auto-fill - Perform the auto-fill function, but get
|
|
;;; the fill-prefix first.
|
|
;;;
|
|
(defun do-indented-auto-fill ()
|
|
"Perform auto-fill, but get fill-prefix first."
|
|
|
|
(let ((opoint (point)))
|
|
(save-excursion
|
|
(move-to-column (1+ fill-column))
|
|
(skip-chars-backward "^ \t\n")
|
|
(if (bolp)
|
|
(re-search-forward "[ \t]" opoint t))
|
|
;; If there is a space on the line before fill-point,
|
|
;; and nonspaces precede it, break the line there.
|
|
(if (save-excursion
|
|
(skip-chars-backward " \t")
|
|
(not (bolp)))
|
|
|
|
;; If we are wrapping to a new line, figure out the indentation on
|
|
;; the current line first.
|
|
(progn
|
|
(setq fill-prefix (get-current-fill opoint))
|
|
(insert ?\n fill-prefix)))))
|
|
; (indent-new-comment-line)))))
|
|
)
|
|
|
|
|
|
;;;
|
|
;;; get-current-fill - Get the fill-prefix for the current line. This
|
|
;;; assumes that the valid fill prefix is between
|
|
;;; (beginning-of-line) and (point).
|
|
;;;
|
|
(defun get-current-fill (pnt)
|
|
"Get the current fill prefix.
|
|
A valid fill prefix must be between the beginning of the line and point."
|
|
|
|
(let ((opoint pnt) fill last-char)
|
|
(save-excursion
|
|
(beginning-of-line)
|
|
(setq fill
|
|
(buffer-substring (point)
|
|
(progn
|
|
(re-search-forward comment-start-skip opoint t)
|
|
(point))))
|
|
|
|
;; Be sure there is trailing white space.
|
|
(setq last-char (substring fill (1- (length fill)) (length fill)))
|
|
(if (and (not (string= " " last-char))
|
|
(not (string= " " last-char)))
|
|
(setq fill (concat fill " ")))
|
|
|
|
(setq fill (replace-letter fill "/" " "))
|
|
|
|
;; Get the hanging indentation if we haven't already.
|
|
(if (and c-comment-hanging-indent (not c-hang-already-done))
|
|
(let ((curr (point))
|
|
(opnt (progn (end-of-line) (point))))
|
|
(beginning-of-line)
|
|
(if (search-forward " - " opnt t)
|
|
(progn
|
|
(setq fill (concat fill (make-string (- (point) curr) 32)))
|
|
(setq c-hang-already-done t)))))
|
|
|
|
;; Set the paragraph delimiters.
|
|
(setq paragraph-start (concat paragraph-start-ref
|
|
"\\|^"
|
|
(regexp-quote
|
|
(substring fill
|
|
0 (1- (length fill))))
|
|
"$"))
|
|
(setq paragraph-separate paragraph-start))
|
|
fill)
|
|
)
|
|
|
|
|
|
;;;
|
|
;;; replace-letter - Given a string, an old letter and a new letter,
|
|
;;; perform the substitution.
|
|
;;;
|
|
(defun replace-letter (str old-letter new-letter)
|
|
(let (new-str c
|
|
(sp 0)
|
|
(size (length str)))
|
|
(while (< sp size)
|
|
(setq c (substring str sp (1+ sp)))
|
|
(setq new-str (concat new-str (if (string= c old-letter) new-letter c)))
|
|
(setq sp (1+ sp)))
|
|
new-str))
|