diff lisp/modes/c-comment.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children e45d5e7c476e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/modes/c-comment.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,301 @@
+;;; c-comment.el --- edit C comments
+
+;; Keywords: c
+
+;;; Copyright (C) 1987, 1988, 1989 Kyle E. Jones
+;;;
+;;; Verbatim copies of this file may be freely redistributed.
+;;;
+;;; Modified versions of this file may be redistributed provided that this
+;;; notice remains unchanged, the file contains prominent notice of
+;;; author and time of modifications, and redistribution of the file
+;;; is not further restricted in any way.
+;;;
+;;; This file is distributed `as is', without warranties of any kind.
+
+;;; Synched up with: Not in FSF.
+
+(provide 'c-comment-edit)
+
+(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.")
+
+(defconst c-comment-leader-regexp "^[ 	]*\\(\\*\\*\\|\\*\\)?[ ]?"
+  "Regexp used to match C comment leaders.")
+
+(defvar c-comment-edit-mode 'text-mode
+  "*Major mode used by `c-comment-edit' when editing C comments.")
+
+(defvar c-comment-edit-hook nil
+  "*Function to call whenever `c-comment-edit' is used.
+The function is called just before the `c-comment-edit' function allows you to
+begin editing the comment.")
+
+(defvar c-comment-edit-buffer-alist nil
+  "Assoc list of C buffers and their associated comment buffers.
+Elements are of the form (C-BUFFER COMMENT-BUFFER COMMENT-START COMMENT-END)
+COMMENT-START and COMMENT-END are markers in the C-BUFFER.")
+
+(defmacro save-point (&rest body)
+  "Save value of point, evalutes FORMS and restore value of point.
+If the saved value of point is no longer valid go to (point-max).
+The variable `save-point' is lambda-bound to the value of point for
+the duration of this call."
+  (list 'let '((save-point (point)))
+	(list 'unwind-protect
+	      (cons 'progn body)
+	      '(goto-char (min (point-max) save-point)))))
+
+(defmacro marker (pos &optional buffer)
+  (list 'set-marker '(make-marker) pos buffer))
+
+
+;;;### autoload
+(defun c-comment-edit (search-prefix)
+  "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.
+
+If point is within a comment, that comment is used.  Otherwise the
+comment to be edited is found by searching forward from point.
+
+With one \\[universal-argument] searching starts after moving back one
+  paragraph.
+With two \\[universal-argument]'s searching starts at the beginning of the
+  current or proceeding C function.
+With three \\[universal-argument]'s searching starts at the beginning of the
+  current page.
+With four \\[universal-argument]'s searching starts at the beginning of the
+  current buffer (clipping restrictions apply).
+
+Once located, the comment is copied into a temporary buffer, the comment
+leaders and delimiters are stripped away and the resulting buffer is
+selected for editing.  The major mode of this buffer is controlled by
+the variable `c-comment-edit-mode'.
+
+Use \\[c-comment-edit-end] when you have finished editing the comment.  The
+comment will be inserted into the original buffer with the appropriate
+delimiters and indention, replacing the old version of the comment.  If
+you don't want your edited version of the comment to replace the
+original, use \\[c-comment-edit-abort]." 
+  (interactive "*P")
+  (let ((c-buffer (current-buffer))
+	marker tem c-comment-fill-column c-comment-buffer
+	c-comment-start c-comment-end
+	(inhibit-quit t))
+    ;; honor search-prefix
+    (cond ((equal search-prefix '(4))
+	   (backward-paragraph))
+	  ((equal search-prefix '(16))
+	   (end-of-defun)
+	   (beginning-of-defun)
+	   (backward-paragraph))
+	  ((equal search-prefix '(64))
+	   (backward-page))
+	  ((equal search-prefix '(256))
+	   (goto-char (point-min))))
+    (if (and (null search-prefix) (setq tem (within-c-comment-p)))
+	(setq c-comment-start (marker (car tem))
+	      c-comment-end (marker (cdr tem)))
+      (let (start end)
+	(condition-case error-data
+	    (save-point
+	      (search-forward "/*")
+	      (setq start (- (point) 2))
+	      (search-forward "*/")
+	      (setq end (point)))
+	  (search-failed (error "No C comment found.")))
+	(setq c-comment-start (marker start))
+	(setq c-comment-end (marker end))))
+    ;; calculate the correct fill-column for the comment
+    (setq c-comment-fill-column (- fill-column
+				   (save-excursion
+				     (goto-char c-comment-start)
+				     (current-column))))
+    ;; create the comment buffer
+    (setq c-comment-buffer
+	  (generate-new-buffer (concat (buffer-name) " *C Comment Edit*")))
+    ;; link into the c-comment-edit-buffer-alist
+    (setq c-comment-edit-buffer-alist
+	  (cons (list (current-buffer) c-comment-buffer
+		      c-comment-start c-comment-end)
+		c-comment-edit-buffer-alist))
+    ;; copy to the comment to the comment-edit buffer
+    (copy-to-buffer c-comment-buffer (+ c-comment-start 2) (- c-comment-end 2))
+    ;; mark the position of point, relative to the beginning of the
+    ;; comment, in the comment buffer.  (iff point is within a comment.)
+    (or search-prefix (< (point) c-comment-start)
+	(setq marker (marker (+ (- (point) c-comment-start 2) 1)
+			     c-comment-buffer)))
+    ;; select the comment buffer for editing
+    (switch-to-buffer c-comment-buffer)
+    ;; remove the comment leaders and delimiters
+    (goto-char (point-min))
+    (while (not (eobp))
+      (and (re-search-forward c-comment-leader-regexp nil t)
+	   (replace-match "" nil t))
+      (forward-line))
+    ;; run appropriate major mode
+    (funcall (or c-comment-edit-mode 'fundamental-mode))
+    ;; override user's default fill-column here since it will lose if
+    ;; the comment is indented in the C buffer.
+    (setq fill-column c-comment-fill-column)
+    ;; delete one leading whitespace char
+    (goto-char (point-min))
+    (if (looking-at "[ \n\t]")
+	(delete-char 1))
+    ;; restore cursor if possible
+    (goto-char (or marker (point-min)))
+    (set-buffer-modified-p nil))
+  ;; run user hook, if present.
+  (if c-comment-edit-hook
+      (funcall c-comment-edit-hook))
+  ;; final admonition
+  (message
+   (substitute-command-keys
+    "Type \\[c-comment-edit-end] to end edit, \\[c-comment-edit-abort] to abort with no change.")))
+
+(defun c-comment-edit-end ()
+  "End c-comment-edit.
+C comment is replaced by its edited counterpart in the appropriate C buffer.
+Indentation will be the same as the original."
+  (interactive)
+  (let ((tuple (find-c-comment-buffer)))
+    (if (null tuple)
+	(error "Not a c-comment-edit buffer."))
+    (let ((inhibit-quit t)
+	  (c-comment-c-buffer (car tuple))
+	  (c-comment-buffer (nth 1 tuple))
+	  (c-comment-start (nth 2 tuple))
+	  (c-comment-end (nth 3 tuple)))
+      (cond
+       ((buffer-modified-p)
+	;; rebuild the comment
+	(goto-char (point-min))
+	(insert "/*\n")
+	(if (string= c-comment-leader "  ")
+	    (while (not (eobp))
+	      (if (not (eolp))
+		  (insert c-comment-leader " "))
+	      (forward-line))
+	  (while (not (eobp))
+	    (insert c-comment-leader (if (eolp) "" " "))
+	    (forward-line)))
+	(if (not (char-equal (preceding-char) ?\n))
+	    (insert "\n"))
+	(insert (if (string= c-comment-leader " *") " */" "*/"))
+	;; indent if necessary
+	(let ((indention
+	       (save-excursion
+		 (set-buffer c-comment-c-buffer)
+		 (goto-char c-comment-start)
+		 (current-column))))
+	  (goto-char (point-min))
+	  (cond ((not (zerop indention))
+		 ;; first line is already indented
+		 ;; in the C buffer
+		 (forward-line)
+		 (while (not (eobp))
+		   (indent-to indention)
+		   (forward-line)))))
+	;; replace the old comment with the new
+	(save-excursion
+	  (set-buffer c-comment-c-buffer)
+	  (save-point
+	    (save-excursion
+	      (delete-region c-comment-start c-comment-end)
+	      (goto-char c-comment-start)
+	      (set-buffer c-comment-buffer)
+	      (append-to-buffer c-comment-c-buffer
+				(point-min) (point-max))))))
+       (t (message "No change.")))
+      ;; switch to the C buffer
+      (if (get-buffer-window c-comment-c-buffer)
+	  (select-window (get-buffer-window c-comment-c-buffer))
+	(switch-to-buffer c-comment-c-buffer))
+      ;; delete the window viewing the comment buffer
+      (and (get-buffer-window c-comment-buffer)
+	   (delete-window (get-buffer-window c-comment-buffer)))
+      ;; unlink the tuple from c-comment-edit-buffer-alist
+      (setq c-comment-edit-buffer-alist
+	    (delq tuple c-comment-edit-buffer-alist))
+      ;; let Emacs reclaim various resources
+      (save-excursion
+	(set-buffer c-comment-buffer)
+	(set-buffer-modified-p nil)
+	(kill-buffer c-comment-buffer))
+      (set-marker c-comment-start nil)
+      (set-marker c-comment-end nil))))
+
+(defun c-comment-edit-abort ()
+  "Abort a c-comment-edit with no change."
+  (interactive)
+  (let* ((tuple (find-c-comment-buffer))
+	 (c-comment-c-buffer (car tuple))
+	 (c-comment-buffer (nth 1 tuple))
+	 (c-comment-start (nth 2 tuple))
+	 (c-comment-end (nth 3 tuple)))
+    (if (null tuple)
+	(error "Not a c-comment-edit buffer."))
+    ;; switch to the C buffer
+    (if (get-buffer-window c-comment-c-buffer)
+	(select-window (get-buffer-window c-comment-c-buffer))
+      (switch-to-buffer c-comment-c-buffer))
+    (let ((inhibit-quit t))
+      (save-excursion
+	(set-buffer c-comment-buffer)
+	(set-buffer-modified-p nil)
+	(kill-buffer c-comment-buffer))
+      ;; unlink the tuple from c-comment-edit-buffer-alist
+      (setq c-comment-edit-buffer-alist
+	    (delq tuple c-comment-edit-buffer-alist))
+      (set-marker c-comment-start nil)
+      (set-marker c-comment-end nil)
+      (message "Aborted with no change."))))
+
+;; this loses on /* /* */ but doing it right would be grim.
+(defun within-c-comment-p ()
+  (condition-case error-data
+      (let (start end)
+	(save-point
+	  (search-backward "/*")
+	  (setq start (point))
+	  (search-forward "*/")
+	  (setq end (point)))
+	(if (< (point) end) (cons start end) nil))
+    (search-failed nil)))
+
+(defun find-c-comment-buffer (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (let ((list c-comment-edit-buffer-alist))
+    (catch 'return-value
+      (while list
+	(if (eq (nth 1 (car list)) buffer)
+	    (throw 'return-value (car list))
+	  (setq list (cdr list)))))))
+	    
+(defun find-c-comment-c-buffer (&optional buffer)
+  (or buffer (setq buffer (current-buffer)))
+  (let ((list c-comment-edit-buffer-alist))
+    (catch 'return-value
+      (while list
+	(if (eq (car (car list)) buffer)
+	    (throw 'return-value (car list))
+	  (setq list (cdr list)))))))
+
+;; keys;
+(define-key mode-specific-map "\e" 'c-comment-edit-end)
+(define-key mode-specific-map "\C-]" 'c-comment-edit-abort)
+
+