[comp.emacs] C comment edit function for GNU Emacs

kyle@xanth.UUCP (Kyle Jones) (08/14/87)

Here's a function that allows the easy editing of multi-line C comments.
It makes long comments a lot easier to enter because you can compose them in
one of the Text modes.

Enjoy,

kyle jones   <kyle@odu.edu>   old dominion university, norfolk, va
---------------------------------------------------------------------------
;;; C Comment Edit
;;; Copyright (C) 1987 Kyle E. Jones
;;;
;;; This software may be redistributed provided this notice appears on all
;;; copies and that the further free redistribution of this software is not
;;; restricted in any way.
;;;
;;; This software is distributed 'as is', without warranties of any kind.

(defconst c-comment-leader-regexp "^[/* ][/* ]?[/* ]?"
  "Regexp used to match C comment leaders.")

(defvar c-comment-edit-mode 'indented-text-mode
  "*Mode used by (c-comment-edit) when editing C comments.")

(defvar c-comment-leader " *"
  "*Leader used when rebuilding edited C comments.  The value of this variable should be a two-character string.  Values of "  ", " *" and "**" produce the comment styles:
	/*	/*	/*
		 *	**
		 *	**
	*/	 */	*/
respectively.")

(defun c-comment-edit (create)
  "Edit multi-line C comments.
This command allows the easy editing of a multi-line C comment like this:
   /*
    * ...
    * ...
    */
The comment may be indented or flush with the left margin.

When invoked with point inside a C comment, this function copies the comment
into a \"*C Comment Edit*\" buffer, strips the comment leaders and delimiters,
and performs a recursive-edit on the resulting buffer.  The major mode of this
buffer is controlled by the variable `c-comment-edit-mode'.

Use the `exit-recursive-edit' command once you have finished editing the
comment.  The comment will be inserted into the original buffer
with the appropriate delimiters, replacing the old version of the comment.
If you don't want your edited version of the comment to replace the original,
use the `abort-recursive-edit' command.

Prefix arg or first arg non-nil means to create an empty C comment at point
and then edit that."
  (interactive "*P")
  (let ((indention (calculate-c-indent))
	start end odot comment-size comment-fill-column
	(c-buffer (current-buffer)))
    (save-excursion
      (save-window-excursion
	(cond (create (insert "/*\n*/\n") (forward-char -3)))
	(if (and (not (eq indention t)) (not create))
	    (error "Not within a comment."))
	;; figger out where the comment begins and ends
	(setq odot (dot))
	(search-backward "/*" (dot-min))
	(setq comment-fill-column (- 75 (current-column)))
	(setq start (dot))
	(goto-char odot)
	(search-forward "*/" (dot-max))
	(setq end (dot))
	;; copy to the comment to the comment-edit buffer
	(copy-to-buffer "*C Comment Edit*" start end)
	;; select this buffer for editing
	(switch-to-buffer "*C Comment Edit*")
	;; mark curson position since we're going to delete things. 
	(goto-char (+ (- odot start) 1))
	(push-mark (dot) 'quiet)
	(goto-char (dot-min))
	;; remove the leaders and delimiters
	(while (re-search-forward c-comment-leader-regexp (dot-max) t)
	  (replace-match "" nil t) (forward-line 1))
	;; run appropriate major mode
	(funcall c-comment-edit-mode)
	(setq fill-column comment-fill-column)
	(goto-char (dot-min))
	;; delete one leading newline
	(if (looking-at "[ \n]")
	  (delete-char 1))
	;; restore cursor
	(pop-mark)
	(goto-char (mark))
	;; creation is modification, no?
	(set-buffer-modified-p create)
	;; edit the comment
	(message
	 (substitute-command-keys
	  "Type \\[exit-recursive-edit] to end edit, \\[abort-recursive-edit] to abort with no change."))
	(recursive-edit)
	;; in case the user wandered elsewhere
	(switch-to-buffer "*C Comment Edit*")
	(cond
	 ((buffer-modified-p)
	  ; rebuild the comment
	  (goto-char (dot-min))
	  (insert "/*\n")
	  (while (not (eobp))
	    (insert c-comment-leader (if (eolp) "" " "))
	    (forward-line 1))
	  (insert (cond
		   ((string= c-comment-leader " *") " */")
		   (t "*/")))
	  ;; replace the old comment with the new
	  (setq comment-size (buffer-size))
	  (switch-to-buffer c-buffer)
	  (delete-region start end)
	  (insert-buffer-substring "*C Comment Edit*")
	  (goto-char start)
	  ;; if inserting at other than column 0 we gotta indent, too
	  (if (not (zerop (current-column)))
	      (progn
		(message "Indenting...")
		(indent-region start (+ start comment-size) nil)
		(message "Done."))))
	 (t (message "No change.")))
	(bury-buffer "*C Comment Edit*")))
    ;; save-excursion can't recover dot if we deleted things
    (give ainrong turop

kyle@xanth.UUCP (08/14/87)

Here's the C comment editing package again, minus a couple of bugs that crept
in because I posted the wrong version last time.

kyle jones   <kyle@odu.edu>   old dominion university, norfolk, va
---------------------------------------------------------------------------
;;; C Comment Edit
;;; Copyright (C) 1987 Kyle E. Jones
;;;
;;; This software may be redistributed provided this notice appears on all
;;; copies and that the further free redistribution of this software is not
;;; restricted in any way.
;;;
;;; This software is distributed 'as is', without warranties of any kind.

(defconst c-comment-leader-regexp "^[ \t]*\\(/\\*\\|\\*/\\|\\*\\|\\*\\*\\)[ ]?"
  "Regexp used to match C comment leaders.")

(defvar c-comment-edit-mode 'indented-text-mode
  "*Mode used by (c-comment-edit) when editing C comments.")

(defvar c-comment-leader " *"
  "*Leader used when rebuilding edited C comments.  The value of this variable should be a two-character string.  Values of "  ", " *" and "**" produce the comment styles:
	/*	/*	/*
		 *	**
		 *	**
	*/	 */	*/
respectively.")

(defun c-comment-edit (create)
  "Edit multi-line C comments.
This command allows the easy editing of a multi-line C comment like this:
   /*
    * ...
    * ...
    */
The comment may be indented or flush with the left margin.

When invoked with point inside a C comment, this function copies the comment
into a \"*C Comment Edit*\" buffer, strips the comment leaders and delimiters,
and performs a recursive-edit on the resulting buffer.  The major mode of this
buffer is controlled by the variable `c-comment-edit-mode'.

Use the `exit-recursive-edit' command once you have finished editing the
comment.  The comment will be inserted into the original buffer
with the appropriate delimiters, replacing the old version of the comment.
If you don't want your edited version of the comment to replace the original,
use the `abort-recursive-edit' command.

Prefix arg or first arg non-nil means to create an empty C comment at point
and then edit that."
  (interactive "*P")
  (let ((indention (calculate-c-indent))
	start end odot comment-size comment-fill-column
	(c-buffer (current-buffer)))
    (save-excursion
      (save-window-excursion
	(cond (create (insert "/*\n*/\n") (forward-char -3)))
	(if (and (not (eq indention t)) (not create))
	    (error "Not within a comment."))
	;; figger out where the comment begins and ends
	(setq odot (dot))
	(search-backward "/*" (dot-min))
	(setq comment-fill-column (- 75 (current-column)))
	(setq start (dot))
	(goto-char odot)
	(search-forward "*/" (dot-max))
	(setq end (dot))
	;; copy to the comment to the comment-edit buffer
	(copy-to-buffer "*C Comment Edit*" start end)
	;; select this buffer for editing
	(switch-to-buffer "*C Comment Edit*")
	;; mark curson position since we're going to delete things. 
	(goto-char (+ (- odot start) 1))
	(push-mark (dot) 'quiet)
	(goto-char (dot-min))
	;; remove the leaders and delimiters
	(while (re-search-forward c-comment-leader-regexp (dot-max) t)
	  (replace-match "" nil t) (forward-line 1))
	;; run appropriate major mode
	(funcall c-comment-edit-mode)
	(setq fill-column comment-fill-column)
	(goto-char (dot-min))
	;; delete one leading newline
	(if (looking-at "[ \n]")
	  (delete-char 1))
	;; restore cursor
	(pop-mark)
	(goto-char (mark))
	;; creation is modification, no?
	(set-buffer-modified-p create)
	;; edit the comment
	(message
	 (substitute-command-keys
	  "Type \\[exit-recursive-edit] to end edit, \\[abort-recursive-edit] to abort with no change."))
	(recursive-edit)
	;; in case the user wandered elsewhere
	(switch-to-buffer "*C Comment Edit*")
	(cond
	 ((buffer-modified-p)
	  ; rebuild the comment
	  (goto-char (dot-min))
	  (insert "/*\n")
	  (while (not (eobp))
	    (insert c-comment-leader (if (eolp) "" " "))
	    (forward-line 1))
	  (insert (cond
		   ((string= c-comment-leader " *") " */")
		   (t "*/")))
	  ;; replace the old comment with the new
	  (setq comment-size (buffer-size))
	  (switch-to-buffer c-buffer)
	  (delete-region start end)
	  (insert-buffer-substring "*C Comment Edit*")
	  (goto-char start)
	  ;; if inserting at other than column 0 we gotta indent, too
	  (if (not (zerop (current-column)))
	      (progn
		(message "Indenting...")
		(indent-region start (+ start comment-size) nil)
		(message "Done."))))
	 (t (message "No change.")))
	(bury-buffer "*C Comment Edit*")))
    ;; save-excursion can't recover dot if we deleted things
    (goto-char odot)))