;;; -*-emacs-lisp-*- ;;; ==================================================================== ;;; @Emacs-Lisp-file{ ;;; author = "Nelson H. F. Beebe", ;;; version = "1.13", ;;; date = "09 March 2010", ;;; time = "08:34:44 MST", ;;; filename = "fmtdep.el", ;;; address = "University of Utah ;;; Department of Mathematics, 110 LCB ;;; 155 S 1400 E RM 233 ;;; Salt Lake City, UT 84112-0090 ;;; USA", ;;; telephone = "+1 801 581 5254", ;;; FAX = "+1 801 581 4148", ;;; URL = "http://www.math.utah.edu/~beebe", ;;; checksum = "51226 279 1288 10687", ;;; email = "beebe@math.utah.edu, beebe@acm.org, ;;; beebe@computer.org (Internet)", ;;; codetable = "ISO/ASCII", ;;; keywords = "GNU Emacs, Makefile, make", ;;; license = "GNU General Public License, version 2", ;;; supported = "yes", ;;; docstring = "This file contains the GNU Emacs command ;;; format-dependency-list for neatly ;;; reformatting a long list of dependents in a ;;; Makefile target, and the command ;;; format-target-list for inserting a list of ;;; targets in a series of comments at point. ;;; ;;; The checksum field above contains a CRC-16 ;;; checksum as the first value, followed by the ;;; equivalent of the standard UNIX wc (word ;;; count) utility output of lines, words, and ;;; characters. This is produced by Robert ;;; Solovay's checksum utility.", ;;; } ;;; ==================================================================== ;;; Edit history (reverse chronological order): ;;; [09-Mar-2010] 1.13 Change magic marker sentinel character ;;; from \377 to \177, because emacs-23.x ;;; fails to match it with (string-equal ...). ;;; [24-Apr-2006] 1.12 Set indentation in ;;; format-dependency-list automatically ;;; according to the position of the ;;; assignment or colon operator, if ;;; possible. ;;; [04-Jul-2005] 1.11 Modify make-clean-and-clobber-targets ;;; to produce separate dependencies on ;;; each LHS. ;;; [01-Nov-2003] 1.10 Update core list in Makefile target clean. ;;; [22-Mar-2003] 1.09 Adjust format-dependency-list to properly ;;; handle fill-column (it was off-by-3 ;;; because of unaccounted-for padding), ;;; and make both fill-column and fill-prefix ;;; locals, exploiting emacs-lisp dynamic binding. ;;; [14-Jul-1998] 1.08 Make minor adjustment in ;;; format-dependency-list to handle case of ;;; region not ending in a newline; the old ;;; version left the \377 magic marker at ;;; the end of the buffer in such a ;;; case. Add (provide 'fmtdep) and define ;;; fmtdep-date and fmtdep-version. ;;; [10-Nov-1997] 1.07 Make minor adjustment in ;;; format-dependency-list to ensure ;;; blanks around equals sign; previously, ;;; if the current column was a multiple ;;; 8, they could be lost. ;;; [25-Sep-1995] 1.06 Update make-clean-and-clobber-targets ;;; to replace obsolete realclean target ;;; by maintainer-clean for GNU standard ;;; Makefile targets. ;;; [04-Feb-1995] 1.05 Rewrite format-dependency-list so that ;;; it avoids region narrowing and widening, ;;; and so that it correctly computes line ;;; lengths during the filling operation. ;;; The old version produced a short first ;;; line because it used NUL for padding, ;;; which counts as two-characters in line ;;; width computation. ;;; Add generation of SHELL line in ;;; make-clean-and-clobber-targets. ;;; [26-Nov-1993] 1.04 Extend format-target-list to handle ;;; multiple targets per line, and add ;;; internal-split-string function. Add ;;; make-clean-and-clobber-targets function. ;;; [11-Oct-1993] 1.03 add support for optional argument to ;;; format-dependency-list ;;; [21-Oct-1992] 1.02 Add standard file header, and remove colons ;;; from format-dependency-list output ;;; [09-Jul-1992] 1.01 Add format-target-list. ;;; [23-Jan-1991] 1.00 Initial version with format-dependency-list. (defconst fmtdep-version "1.13") ;NB: update this at every change (defconst fmtdep-date "[09-Mar-2010]") ;NB: update this at every change (provide 'fmtdep) (defun format-dependency-list (&optional ntabs) "Collapse the Makefile dependency list beginning on the current line, then refill it with continuation lines." (interactive "P") ;; version 1.12 [24-Apr-2006]: set ntabs automatically according to ;; position of assignment operator, if possible (beginning-of-line) (if (looking-at "^[^:=]*[:=]") (progn (beginning-of-line) (re-search-forward "[:=]") (backward-char 1) (setq ntabs (/ (+ (current-column) 7) 8))) (setq ntabs (if ntabs (prefix-numeric-value ntabs) 3))) (internal-collapse-Makefile-list) (beginning-of-line) (save-excursion (let* ((beg (point)) (end) (start-prefix) (old-fill-column fill-column) (fill-column (- old-fill-column 3)) (fill-prefix)) (setq fill-prefix (concat (make-string ntabs 9) " ")) (goto-char beg) (re-search-forward "[:=]") (backward-char 1) ;; We require a printable character for padding in order for ;; fill-region and current-column to work correctly, so we ;; choose a tilde as the least-likely candidate. We therefore ;; check for the presence of one first, so as to avoid an ;; editing disaster when we later replace tildes by spaces. (save-excursion (forward-line 1) (setq end (point)) (goto-char beg) (if (search-forward "~" end t) (error "Cannot handle dependency list containing a tilde"))) ;; Supply spaces after :, and before = by inserting ;; column-padding chars before filling the region. (cond ((looking-at "=") (delete-horizontal-space) (insert-char ?\~ (max 1(- (* 8 ntabs) (current-column)))) (forward-char 1) (if (not (looking-at "[ \t]")) (progn (insert " ") (forward-char -1))) (forward-char -1)) ((looking-at ":") (delete-horizontal-space) (forward-char 1) (delete-horizontal-space) (insert-char ?\~ (- (+ 2 (* 8 ntabs)) (current-column))))) ;; The job region is now the current line, so remember its end ;; and insert a magic marker just past the end so that we can ;; detect end-of-region in the searches below. (forward-line 1) (if (not (string-equal "\n" (buffer-substring (1- (point)) (point)))) (insert "\n")) ;ensure region ends with newline (setq end (point)) (insert-char ?\177 1) ;install magic end-of-region marker (fill-region beg end) ;do the formatting work ;; Replace tildes by spaces in our job region (goto-char beg) (while (and (< (point) end) (search-forward "~" end t)) (replace-match " " nil t)) ;; Finally, replace newline by space-backslash-newline in our ;; job region. We use the end-of-region marker in the loop ;; termination condition, since the substitutions invalidate the ;; end variable. (goto-char beg) (catch 'DONE (while (search-forward "\n" nil t) (if (string-equal (buffer-substring (point) (1+ (point))) "\177") (throw 'DONE nil)) (replace-match " \\\n" nil t))) (if (string-equal (buffer-substring (point) (1+ (point))) "\177") (delete-char 1)) ))) (defun format-target-list (&optional do-sort) "Insert in the Makefile at the current line a list of targets found in the Makefile. With an argument, the targets are sorted alphabetically." (interactive) (let ((colon nil) (s "") (start)) (save-excursion (goto-char (point-min)) (while (re-search-forward "^[^\t #:=.][^#:=]*:" nil t) (setq colon (point)) (beginning-of-line) (if (not (looking-at "^[.]")) ;bug workaround: re-search-forward finds (mapcar '(lambda (str) ;. at start of line (setq s (format "%s#\t%s\n" s str))) (internal-split-string (buffer-substring (point) (1- colon)) " "))) (forward-line 1))) (beginning-of-line) (insert "# Current target list:\n") (setq start (point)) (insert s) (if (or do-sort current-prefix-arg) (sort-lines nil start (point))))) (defun internal-collapse-Makefile-list () "Collapse the Makefile dependency list beginning on the current line, joining consecutive lines that end with a backslash." (catch 'EXIT (while t (end-of-line) (backward-char 1) (if (looking-at "\\\\$") (progn (delete-char 2) (just-one-space)) (throw 'EXIT nil))))) (defun internal-split-string (s fs) "Split a string S into words separated by FS, and return it as a list of words. Leading and trailing FS characters are ignored." (let ((k 0) (n (length s)) (start) (end)) (if (> n 0) (progn (while (and (< k n) (string-equal (substring s k (1+ k)) fs)) (setq k (1+ k))) (setq start k) (while (and (< k n) (not (string-equal (substring s k (1+ k)) fs))) (setq k (1+ k))) (setq end k) (while (and (< k n) (string-equal (substring s k (1+ k)) fs)) (setq k (1+ k))) (cons (substring s start end) (internal-split-string (substring s k) fs))) nil))) (defun make-clean-and-clobber-targets () "Insert standard clean and clobber targets in the Makefile at the current point, along with GNU standard equivalents." (interactive) (beginning-of-line) (insert "clean:\n" "\t-$(RM) *.i\n" "\t-$(RM) *.o\n" "\t-$(RM) *~\n" "\t-$(RM) \\#*\n" "\t-$(RM) a.out\n" "\t-$(RM) core core.*\n" "\n") (insert "clobber:\tdistclean\n\n") (insert "distclean:\tmostlyclean\n\n") (insert "maintainer-clean:\tdistclean\n" "\t@echo \"This command is intended for maintainers to use;\"\n" "\t@echo \"it deletes files that may require special tools to rebuild.\"\n\n") (insert "mostlyclean: clean\n\n") (save-excursion (goto-char (point-min)) (if (not (re-search-forward "^SHELL[ \t]*=" nil t)) (progn (goto-char (point-min)) (re-search-forward "^[^#]") (beginning-of-line) (insert "\nSHELL\t\t= /bin/sh\n\n"))) (if (not (re-search-forward "^RM[ \t]*=" nil t)) (progn (goto-char (point-min)) (re-search-forward "^[^#]") (beginning-of-line) (insert "\nRM\t\t= /bin/rm -f\n\n")))))