weiner@novavax.UUCP (Bob Weiner) (09/22/89)
I have been unable to reach psm@cbnewse.ATT.COM (Steve Murphy) by mail,
so this is in reply to his message of 14 Sep 89 20:51:17 GMT posted to
this group.
He writes:
With all the talk about formatting, I thought I'd ask if
anyone has elisp code to change comments that look like:
/* comment */
or
/*
comment
*/
to
/*
* comment
*/
The above code would fill the comment correctly, also.
The last function in this code does what you want. The rest refills
such comments properly. (This code was posted a number of months back
but a number of problems that this code solves have come up in recent
postings.)
;;!emacs
;;
;; FILE: par-align.el
;; SUMMARY: Improved paragraph fill and align functions
;; USAGE: GNU Emacs Lisp Library
;;
;; AUTHOR: Bob Weiner, Applied Research, Motorola, Inc.
;; E-MAIL: USENET: weiner@novavax.UUCP
;; ORIG-DATE: 14-Apr-89
;; LAST-MOD: 18-Aug-89 at 23:26:17 by Bob Weiner
;;
;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc.
;; Available for use and distribution under the same terms as GNU Emacs.
;;
;; This file is not yet part of GNU Emacs.
;;
;; DESCRIPTION:
;;
;; This package allows GNU Emacs paragraph commands to deal more
;; reasonably with indented text and embedded comments. It lets you
;; realign and set the fill prefix on one line of a paragraph, e.g. the
;; first, and then have all the other lines match up when you fill the
;; paragraph.
;;
;; I think the 'fill-paragraph-and-align' command eliminates the need for
;; Kyle Jones, 'C Comment Edit' package. Additionally, there is no need
;; to edit in a special buffer.
;;
;; If you set the fill-prefix to some value, then set it to nil (set it at
;; the beginning of a line) and then fill the paragraph, the old
;; fill-prefix will be stripped off and the paragraph will be filled
;; properly with no prefix. Then just add the new fill-prefix, if any,
;; that you want and refill again.
;;
;; If you have ever tried to fill Emacs Lisp documentation strings or
;; embedded comments, you know that all you get is an ugly mess. You end
;; up having to fill after putting blank lines at the beginning and end.
;; Now you can fill properly without making any inline changes. The fill
;; routines do not fill the first line of documentation strings since it is
;; used by the apropos commands and may intentionally be short.
;;
;; The fill and movement commands also recognize multiple paragraphs
;; within a single comment stretch, just like the ones you see in this
;; description text. Just remember to set the fill prefix properly, just
;; as you normally would for the fill-paragraph command.
;;
;; When filling a region, fill-prefix-prev (old fill prefix) can be
;; replaced by fill-prefix throughout the entire region before each
;; paragraph is filled. Simply call the 'fill-region-and-align-all'
;; command.
;;
;; Always fill with point before some of the text to be filled. If you
;; try to fill when point is on a line following all of the text to be
;; filled, the next paragraph may be filled by mistake, e.g. when filling
;; with point near the end of a comment string.
;;
;; C comments of the form (with any number of '*' chars):
;; /*
;; * <text>
;; * <text>
;; */
;; are filled well.
;;
;; Multiple line C comments of the form:
;; /* */
;; /* */
;; are not filled well, so don't use them. If you have some already, you
;; can convert them to the kind above with the
;; 'c-comment-make-prefix-only' command found in this package.
;;
;; Comments in UNIX shell scripts of the form (with any number of '#' chars):
;; #
;; # <text>
;; # <text>
;; #
;; are filled well if the first line of the file begins with a pattern that
;; matches the regular expression "^#!/bin/[ck]?sh" as shell scripts should.
;;
;; Fortran comments of the form:
;; C
;; C <text>
;; C <text>
;; C
;; are filled well.
;;
;; The commands bound immediately below do all of this work.
;;
;; DESCRIP-END.
;; Suggested key bindings
;;
(global-set-key "\M-j" 'fill-paragraph-and-align)
(global-set-key "\C-x\C-j" 'fill-region-and-align-all)
(define-key text-mode-map "\C-x\C-j" 'fill-region-and-align)
(define-key indented-text-mode-map "\C-x\C-j" 'fill-region-and-align)
(define-key outline-mode-map "\C-x\C-j" 'fill-region-and-align)
;; The next two functions are suitable as replacements for the standard
;; paragraph movement commands if you want them to recognize paragraph
;; boundaries the way the fill functions below do.
;;
;; Suggested key bindings
;;
;;(global-set-key "\M-n" 'forward-para)
;;(global-set-key "\M-p" 'backward-para)
(defun forward-para (&optional arg)
"Move forward to end of paragraph. With ARG, do it arg times.
A line which paragraph-start matches either separates paragraphs,
if paragraph-separate matches it also, or is the first line of a paragraph.
A paragraph end is the beginning of a line which is not part of the paragraph
to which the end of the previous line belongs, or the end of the buffer."
(interactive "p")
(paragraph-filter 'forward-paragraph arg))
(defun backward-para (&optional arg)
"Move backward to start of paragraph. With ARG, do it arg times.
A paragraph start is the beginning of a line which is a first-line-of-paragraph
or which is ordinary text and follows a paragraph-separating line, except
if the first real line of a paragraph is preceded by a blank line,
the paragraph starts at that blank line.
See forward-paragraph for more information."
(interactive "p")
(or arg (setq arg 1))
(paragraph-filter 'forward-paragraph (- arg)))
(defconst fill-prefix-prev nil
"Previous string inserted at front of new line during filling, or nil for none.
Setting this variable automatically makes it local to the current buffer.")
(make-variable-buffer-local 'fill-prefix-prev)
;; Redefine this function so that it sets 'fill-prefix-prev' also.
(defun set-fill-prefix ()
"Set the fill-prefix to the current line up to point.
Also sets fill-prefix-prev to previous value of fill-prefix.
Filling expects lines to start with the fill prefix and reinserts the fill
prefix in each resulting line."
(interactive)
(setq fill-prefix-prev fill-prefix
fill-prefix (buffer-substring
(save-excursion (beginning-of-line) (point))
(point)))
(if (equal fill-prefix-prev "")
(setq fill-prefix-prev nil))
(if (equal fill-prefix "")
(setq fill-prefix nil))
(if fill-prefix
(message "fill-prefix: \"%s\"" fill-prefix)
(message "fill-prefix cancelled")))
(defun fill-paragraph-and-align (justify-flag)
"Fill current paragraph. Prefix arg JUSTIFY-FLAG means justify as well.
Does not alter fill prefix on first line of paragraph. Any whitespace
separated version of the fill-prefix, or fill-prefix-prev when fill-prefix is
nil, at the beginning of lines is deleted before the fill is performed. This
aligns all lines in a paragraph properly after the fill-prefix is changed.
Works well within text, singly delimited C comments, Lisp comments and
documentation strings, and Fortran comments."
(interactive "P")
(paragraph-filter 'fill-para-align justify-flag))
(defun fill-region-and-align-all (justify-flag)
"Fill each line in region. Prefix arg JUSTIFY-FLAG means justify as well.
Replace any whitespace separated version of fill-prefix-prev with fill-prefix
in all lines of region. This aligns all lines throughout the region properly
after the fill-prefix is changed. Works well within text, singly delimited C
comments, UNIX shell scripts, Lisp comments and documentation strings, and
Fortran comments.
See also documentation for fill-region-and-align."
(interactive "P")
(paragraph-filter 'fill-region-align justify-flag t))
(defun fill-region-and-align (justify-flag &optional align-all)
"Fill each line in region. Prefix arg JUSTIFY-FLAG means justify as well.
Optional ALIGN-ALL non-nil means replace fill-prefix-prev with fill-prefix in
all lines of region, otherwise, does not alter prefix in paragraph separator
lines and first lines of paragraphs.
Any whitespace separated version of fill-prefix, or fill-prefix-prev when
fill-prefix is nil, at the beginning of appropriate lines is removed before the
fill is performed. This aligns all lines in a paragraph properly after the
fill-prefix is changed. Works well within text, singly delimited C comments,
UNIX shell scripts, Lisp comments and documentation strings, and Fortran comments."
(interactive "P")
(paragraph-filter 'fill-region-align justify-flag align-all))
(defun paragraph-filter (func arg1 &optional arg2)
;;; LISP C Fortran
;;; ----------------------------------------
;;; comment-start ";" "/* " nil (^[Cc*])
;;; comment-start-skip ";+ *" "/\\*+ *" "![ \t]*"
;;; comment-end "" ([^J^L]) " */" "" (^J)
;;;
(let* ((*lsp* (or (eq major-mode 'emacs-lisp-mode)
(eq major-mode 'lisp-interaction-mode)
(eq major-mode 'scheme-mode)
(eq major-mode 'lisp-mode)))
(*txt* (or (eq major-mode 'text-mode)
(eq major-mode 'indented-text-mode)
(eq major-mode 'outline-mode)
(eq major-mode 'picture-mode)))
(extra-para-sep
(concat "^"
;; Don't change the '?' in the following lines to a '+', it
;; will break certain fill boundary conditions.
(if (eq major-mode 'fortran-mode) "[cC*]?")
"[ \t]*\\("
(cond ((string-match "^#!/bin/[ck]?sh"
(buffer-substring 1 11))
"#*")
;; Don't change the '?' in the following lines to a '+', it
;; will break certain fill boundary conditions.
(comment-start-skip
(concat "\\(" comment-start-skip "\\)?")))
(if (eq major-mode 'c-mode) "\\|\*+/?")
"\\)[ \t]*$"
(if *lsp* "\\|^[ \t]*\\([[(]\\|\"\\)")
;; Mainly for Interleaf TPS markup documents
(if *txt* "\\|^[@<]")
))
(paragraph-separate
(concat paragraph-separate "\\|" extra-para-sep))
(paragraph-start
(concat paragraph-start "\\|" extra-para-sep)))
(if arg2
(funcall func arg1 arg2)
(funcall func arg1))))
(defun fill-region-align (justify-flag &optional align-all)
(if align-all
(replace-fill-str fill-prefix-prev fill-prefix))
(save-excursion
(let ((end (max (point) (mark))))
(goto-char (min (point) (mark)))
(while (and (not (eobp)) (< (point) end))
(fill-para-align justify-flag align-all)
(forward-paragraph)
;; Forward to real paragraph end if not in lisp mode
(or *lsp* (re-search-forward (concat "\\'\\|" paragraph-separate)))))))
(defun fill-para-align (justify-flag &optional leave-prefix)
(save-excursion
(end-of-line)
;; Backward to para begin
(re-search-backward (concat "\\`\\|" paragraph-separate))
(forward-line (if (looking-at extra-para-sep) 2 1))
(let ((region-start (point)))
(forward-line -1)
(let ((from (point)))
(forward-paragraph)
;; Forward to real paragraph end if not in lisp mode
(or *lsp* (re-search-forward (concat "\\'\\|" paragraph-separate)))
(beginning-of-line)
(or leave-prefix
(replace-fill-str
(or fill-prefix fill-prefix-prev)
"" nil region-start (point)))
(fill-region-as-paragraph from (point) justify-flag)))))
(defun replace-fill-str (fill-str-prev fill-str &optional suffix start end)
"Replace whitespace separated FILL-STR-PREV with FILL-STR.
Optional SUFFIX non-nil means replace at ends of lines, default is beginnings.
Optional arguments START and END specify the replace region, default is the
current region."
(if fill-str-prev
(progn (if (not start) (setq start (min (point) (mark))))
(if (not end) (setq end (max (point) (mark))))
(if (not fill-str) (setq fill-str ""))
(save-excursion
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(perform-replace
(concat
(if suffix nil "^")
"[ \t]*"
(regexp-quote
;; Get non-whitespace separated fill-str-prev
(substring
fill-str-prev
(or (string-match "[^ \t]" fill-str-prev) 0)
(if (string-match
"[ \t]*\\(.*[^ \t]\\)[ \t]*$" fill-str-prev)
(match-end 1))))
"[ \t]*"
(if suffix "$"))
fill-str nil t nil))))))
(defun c-comment-make-prefix-only ()
"Make multiply-delimited C comments in region singly delimited.
Converts comments of form:
/* <text> */ to /*
/* <text> */ * <text>
* <text>
*/"
(interactive)
(replace-fill-str "/*" " * ")
(replace-fill-str "*/" "" t)
(save-excursion
(goto-char (min (point) (mark)))
(insert "/*\n"))
(save-excursion
(goto-char (max (point) (mark)))
(insert (if (bolp) " */\n" "\n */"))))
(provide 'par-align)
--
Bob Weiner, Motorola, Inc., USENET: ...!gatech!uflorida!novavax!weiner
(407) 738-2087