aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1996-02-06 19:07:41 +0000
committerRichard M. Stallman1996-02-06 19:07:41 +0000
commitd5eead69fe6e9053ff20475b59539f95bea2589e (patch)
treefa3f76a8f512dbeaad6b3122ab6d2b32a67fa53c
parent21a36d2362ebdae00de21af05c2d75292870b17b (diff)
downloademacs-d5eead69fe6e9053ff20475b59539f95bea2589e.tar.gz
emacs-d5eead69fe6e9053ff20475b59539f95bea2589e.zip
(lm-header-prefix): New variable.
(lm-comment-column): defvar moved. (lm-history-header, lm-commentary-header): New variables. (lm-get-header-re, lm-get-package-name): New functions. (lm-code-mark): defun --> defsubst. (lm-history-mark, lm-commentary-mark): New functions. (lm-header): Now accepts RCS ident style headers. (lm-summary): Now accepts unix `what' commands prefix @(#). (lm-crack-address, lm-authors, lm-maintainer, lm-insert-at-column): (lm-creation-date, lm-last-modified-date, lm-version): (lm-keywords, lm-adapted-by): Comments made into doc strings. (lm-commentary): Added more tolerant 'cond' case. Now uses functions lm-commentary-mark, lm-... to get points. (lm-verify): Made interactive. Added more check points in the last prog1. (lm-synopsis): Made interactive.
-rw-r--r--lisp/emacs-lisp/lisp-mnt.el326
1 files changed, 221 insertions, 105 deletions
diff --git a/lisp/emacs-lisp/lisp-mnt.el b/lisp/emacs-lisp/lisp-mnt.el
index 05e7f58d321..4ca62544bc1 100644
--- a/lisp/emacs-lisp/lisp-mnt.el
+++ b/lisp/emacs-lisp/lisp-mnt.el
@@ -5,7 +5,7 @@
5;; Author: Eric S. Raymond <esr@snark.thyrsus.com> 5;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
6;; Maintainer: Eric S. Raymond <esr@snark.thyrsus.com> 6;; Maintainer: Eric S. Raymond <esr@snark.thyrsus.com>
7;; Created: 14 Jul 1992 7;; Created: 14 Jul 1992
8;; Version: $Id: lisp-mnt.el,v 1.13 1996/01/25 00:55:13 kwzh Exp rms $ 8;; Version: $Id: lisp-mnt.el,v 1.14 1996/02/04 21:30:40 rms Exp rms $
9;; Keywords: docs 9;; Keywords: docs
10;; X-Bogus-Bureaucratic-Cruft: Gruad will get you if you don't watch out! 10;; X-Bogus-Bureaucratic-Cruft: Gruad will get you if you don't watch out!
11 11
@@ -22,9 +22,8 @@
22;; GNU General Public License for more details. 22;; GNU General Public License for more details.
23 23
24;; You should have received a copy of the GNU General Public License 24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs; see the file COPYING. If not, write to the 25;; along with GNU Emacs; see the file COPYING. If not, write to
26;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 26;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27;; Boston, MA 02111-1307, USA.
28 27
29;;; Commentary: 28;;; Commentary:
30 29
@@ -117,71 +116,137 @@
117(require 'picture) ; provides move-to-column-force 116(require 'picture) ; provides move-to-column-force
118(require 'emacsbug) 117(require 'emacsbug)
119 118
119;;; Variables:
120
121(defconst lm-header-prefix "^;;*[ \t]+\\(@\(#\)\\)?[ \t]*\\([\$]\\)?"
122 "Prefix that is ignored before the tag.
123Eg. you can write the 1st line synopsis string and headers like this
124in your lisp package:
125
126 ;; @(#) package.el -- pacakge description
127 ;;
128 ;; @(#) $Maintainer: Person Foo Bar $
129
130The @(#) construct is used by unix what(1) and
131then $identifier: doc string $ is used by GNU ident(1)")
132
133(defconst lm-comment-column 16
134 "Column used for placing formatted output.")
135
136(defconst lm-commentary-header "Commentary\\|Documentation"
137 "Regexp which matches start of documentation section.")
138
139(defconst lm-history-header "Change Log\\|History"
140 "Regexp which matches the start of code log section.")
141
142;;; Functions:
143
120;; These functions all parse the headers of the current buffer 144;; These functions all parse the headers of the current buffer
121 145
122(defun lm-section-mark (hd &optional after) 146(defsubst lm-get-header-re (header &optional mode)
123 ;; Return the buffer location of a given section start marker 147 "Returns regexp for matching HEADER. If called with optional MODE and
148with value 'section, return section regexp instead."
149 (cond
150 ((eq mode 'section)
151 (concat "^;;;;* " header ":[ \t]*$"))
152 (t
153 (concat lm-header-prefix header ":[ \t]*"))))
154
155(defsubst lm-get-package-name ()
156 "Returns package name by looking at the first line."
157 (save-excursion
158 (goto-char (point-min))
159 (if (and (looking-at (concat lm-header-prefix))
160 (progn (goto-char (match-end 0))
161 (looking-at "\\([^\t ]+\\)")
162 (match-end 1)))
163 (buffer-substring (match-beginning 1) (match-end 1))
164 )))
165
166(defun lm-section-mark (header &optional after)
167 "Return the buffer location of a given section start marker.
168The HEADER is section mark string to find and AFTER is non-nil
169returns location of next line."
124 (save-excursion 170 (save-excursion
125 (let ((case-fold-search t)) 171 (let ((case-fold-search t))
126 (goto-char (point-min)) 172 (goto-char (point-min))
127 (if (re-search-forward (concat "^;;;;* " hd ":[ \t]*$") nil t) 173 (if (re-search-forward (lm-get-header-re header 'section) nil t)
128 (progn 174 (progn
129 (beginning-of-line) 175 (beginning-of-line)
130 (if after (forward-line 1)) 176 (if after (forward-line 1))
131 (point)) 177 (point))
132 nil)))) 178 nil))))
133 179
134(defun lm-code-mark () 180(defsubst lm-code-mark ()
135 ;; Return the buffer location of the code start marker 181 "Return the buffer location of the 'Code' start marker."
136 (lm-section-mark "Code")) 182 (lm-section-mark "Code"))
137 183
138(defun lm-header (hd) 184(defsubst lm-commentary-mark ()
139 ;; Return the contents of a named header 185 "Return the buffer location of the 'Commentary' start marker."
186 (lm-section-mark lm-commentary-header))
187
188(defsubst lm-history-mark ()
189 "Return the buffer location of the 'history' start marker."
190 (lm-section-mark lm-history-header))
191
192(defun lm-header (header)
193 "Return the contents of a named HEADER."
140 (goto-char (point-min)) 194 (goto-char (point-min))
141 (let ((case-fold-search t)) 195 (let ((case-fold-search t))
142 (if (re-search-forward 196 (if (and (re-search-forward (lm-get-header-re header) (lm-code-mark) t)
143 (concat "^;; " hd ": \\(.*\\)") (lm-code-mark) t) 197 ;; RCS ident likes format "$identifier: data$"
198 (looking-at "\\([^$\n]+\\)")
199 (match-end 1))
144 (buffer-substring (match-beginning 1) (match-end 1)) 200 (buffer-substring (match-beginning 1) (match-end 1))
145 nil))) 201 nil)))
146 202
147(defun lm-header-multiline (hd) 203(defun lm-header-multiline (header)
148 ;; Return the contents of a named header, with possible continuation lines. 204 "Return the contents of a named HEADER, with possible continuation lines.
149 ;; Note -- the returned value is a list of strings, one per line. 205The returned value is a list of strings, one per line."
150 (save-excursion 206 (save-excursion
151 (goto-char (point-min)) 207 (goto-char (point-min))
152 (let ((res (save-excursion (lm-header hd)))) 208 (let ((res (lm-header header)))
153 (if res 209 (cond
154 (progn 210 (res
155 (forward-line 1) 211 (setq res (list res))
156 (setq res (list res)) 212 (forward-line 1)
157 (while (looking-at "^;;\t\\(.*\\)") 213
158 (setq res (cons (buffer-substring 214 (while (and (looking-at (concat lm-header-prefix "[\t ]+"))
159 (match-beginning 1) 215 (progn
160 (match-end 1)) 216 (goto-char (match-end 0))
161 res)) 217 (looking-at "\\(.*\\)"))
162 (forward-line 1)) 218 (match-end 1))
163 )) 219 (setq res (cons (buffer-substring
164 res))) 220 (match-beginning 1)
221 (match-end 1))
222 res))
223 (forward-line 1))
224 ))
225 res
226 )))
165 227
166;; These give us smart access to the header fields and commentary 228;; These give us smart access to the header fields and commentary
167 229
168(defun lm-summary (&optional file) 230(defun lm-summary (&optional file)
169 ;; Return the buffer's or FILE's one-line summary. 231 "Return the buffer's or optional FILE's one-line summary."
170 (save-excursion 232 (save-excursion
171 (if file 233 (if file
172 (find-file file)) 234 (find-file file))
173 (goto-char (point-min)) 235 (goto-char (point-min))
174 (prog1 236 (prog1
175 (if (looking-at "^;;; [^ ]+ --- \\(.*\\)") 237 (if (and
238 (looking-at lm-header-prefix)
239 (progn (goto-char (match-end 0))
240 (looking-at "[^ ]+[ \t]+--+[ \t]+\\(.*\\)")))
176 (buffer-substring (match-beginning 1) (match-end 1))) 241 (buffer-substring (match-beginning 1) (match-end 1)))
177 (if file 242 (if file
178 (kill-buffer (current-buffer))) 243 (kill-buffer (current-buffer)))
179 ))) 244 )))
180 245
181
182(defun lm-crack-address (x) 246(defun lm-crack-address (x)
183 ;; Given a string containing a human and email address, parse it 247 "Cracks email address from string.
184 ;; into a cons pair (name . address). 248Given a string 'x' containing a human and email address, parse it
249into a cons pair (NAME . ADDRESS)."
185 (cond ((string-match "\\(.+\\) [(<]\\(\\S-+@\\S-+\\)[>)]" x) 250 (cond ((string-match "\\(.+\\) [(<]\\(\\S-+@\\S-+\\)[>)]" x)
186 (cons (substring x (match-beginning 1) (match-end 1)) 251 (cons (substring x (match-beginning 1) (match-end 1))
187 (substring x (match-beginning 2) (match-end 2)))) 252 (substring x (match-beginning 2) (match-end 2))))
@@ -194,9 +259,9 @@
194 (cons x nil)))) 259 (cons x nil))))
195 260
196(defun lm-authors (&optional file) 261(defun lm-authors (&optional file)
197 ;; Return the buffer's or FILE's author list. Each element of the 262 "Return the buffer's or optional FILE's author list. Each element of the
198 ;; list is a cons; the car is a name-aming-humans, the cdr an email 263list is a cons; the car is a name-aming-humans, the cdr an email
199 ;; address. 264address."
200 (save-excursion 265 (save-excursion
201 (if file 266 (if file
202 (find-file file)) 267 (find-file file))
@@ -208,9 +273,9 @@
208 )))) 273 ))))
209 274
210(defun lm-maintainer (&optional file) 275(defun lm-maintainer (&optional file)
211 ;; Get a package's bug-report & maintenance address. Parse it out of FILE, 276 "Seearch for 'maintainer'. Get a package's bug-report & maintenance address.
212 ;; or the current buffer if FILE is nil. 277Parse it out of FILE, or the current buffer if FILE is nil.
213 ;; The return value is a (name . address) cons. 278The return value is a (NAME . ADDRESS) cons."
214 (save-excursion 279 (save-excursion
215 (if file 280 (if file
216 (find-file file)) 281 (find-file file))
@@ -224,8 +289,8 @@
224 ))) 289 )))
225 290
226(defun lm-creation-date (&optional file) 291(defun lm-creation-date (&optional file)
227 ;; Return a package's creation date, if any. Parse it out of FILE, 292 "Seearch for 'created'. Return a package's creation date, if any.
228 ;; or the current buffer if FILE is nil. 293Parse it out of FILE, or the current buffer if FILE is nil."
229 (save-excursion 294 (save-excursion
230 (if file 295 (if file
231 (find-file file)) 296 (find-file file))
@@ -237,7 +302,7 @@
237 302
238 303
239(defun lm-last-modified-date (&optional file) 304(defun lm-last-modified-date (&optional file)
240 ;; Return a package's last-modified date, if you can find one. 305 "Return a package's last-modified date, if it has one."
241 (save-excursion 306 (save-excursion
242 (if file 307 (if file
243 (find-file file)) 308 (find-file file))
@@ -260,8 +325,8 @@
260 ))) 325 )))
261 326
262(defun lm-version (&optional file) 327(defun lm-version (&optional file)
263 ;; Return the package's version field. 328 "Search for RCS identifier '$Id'. Return the package's version field.
264 ;; If none, look for an RCS or SCCS header to crack it out of. 329If none, look for an RCS or SCCS header to crack it out of."
265 (save-excursion 330 (save-excursion
266 (if file 331 (if file
267 (find-file file)) 332 (find-file file))
@@ -290,8 +355,8 @@
290 ))) 355 )))
291 356
292(defun lm-keywords (&optional file) 357(defun lm-keywords (&optional file)
293 ;; Return the header containing the package's topic keywords. 358 "Search for 'keywords'. Return the header containing the package's
294 ;; Parse them out of FILE, or the current buffer if FILE is nil. 359topic keywords. Parse them out of FILE, or the current buffer if FILE is nil."
295 (save-excursion 360 (save-excursion
296 (if file 361 (if file
297 (find-file file)) 362 (find-file file))
@@ -303,9 +368,9 @@
303 ))) 368 )))
304 369
305(defun lm-adapted-by (&optional file) 370(defun lm-adapted-by (&optional file)
306 ;; Return the name or code of the person who cleaned up this package 371 "Search for 'adapted-by'. Return the name or code of the person who
307 ;; for distribution. Parse it out of FILE, or the current buffer if 372cleaned up this package for distribution. Parse it out of FILE, or
308 ;; FILE is nil. 373the current buffer if FILE is nil."
309 (save-excursion 374 (save-excursion
310 (if file 375 (if file
311 (find-file file)) 376 (find-file file))
@@ -316,79 +381,129 @@
316 ))) 381 )))
317 382
318(defun lm-commentary (&optional file) 383(defun lm-commentary (&optional file)
319 ;; Return the commentary region of a file, as a string. 384 "Return the commentary region of a file, as a string.
385The area is started with tag 'Commentary' and eded with tag
386'Change Log' or 'History'."
320 (save-excursion 387 (save-excursion
321 (if file 388 (if file
322 (find-file file)) 389 (find-file file))
323 (prog1 390 (prog1
324 (let ((commentary (lm-section-mark "Commentary" t)) 391 (let ((commentary (lm-commentary-mark))
325 (change-log (lm-section-mark "Change Log")) 392 (change-log (lm-history-mark))
326 (code (lm-section-mark "Code"))) 393 (code (lm-code-mark))
327 (and commentary 394 )
328 (if change-log 395 (cond
329 (buffer-substring commentary change-log) 396 ((and commentary change-log)
330 (buffer-substring commentary code))) 397 (buffer-substring commentary change-log))
331 ) 398 ((and commentary code)
399 (buffer-substring commentary code))
400 (t
401 nil)))
332 (if file 402 (if file
333 (kill-buffer (current-buffer))) 403 (kill-buffer (current-buffer)))
334 ))) 404 )))
335 405
336;;; Verification and synopses 406;;; Verification and synopses
337 407
338(defun lm-insert-at-column (col &rest pieces) 408(defun lm-insert-at-column (col &rest strings)
339 (if (> (current-column) col) (insert "\n")) 409 "Insert list of STRINGS, at column COL."
340 (move-to-column-force col) 410 (if (> (current-column) col) (insert "\n"))
341 (apply 'insert pieces)) 411 (move-to-column-force col)
412 (apply 'insert strings))
342 413
343(defconst lm-comment-column 16) 414(defun lm-verify (&optional file showok &optional verb)
344
345(defun lm-verify (&optional file showok)
346 "Check that the current buffer (or FILE if given) is in proper format. 415 "Check that the current buffer (or FILE if given) is in proper format.
347If FILE is a directory, recurse on its files and generate a report into 416If FILE is a directory, recurse on its files and generate a report into
348a temporary buffer." 417a temporary buffer."
349 (if (and file (file-directory-p file)) 418 (interactive)
350 (progn 419 (let* ((verb (or verb (interactive-p)))
351 (switch-to-buffer (get-buffer-create "*lm-verify*")) 420 ret
352 (erase-buffer) 421 name
353 (mapcar 422 )
354 '(lambda (f) 423 (if verb
355 (if (string-match ".*\\.el$" f) 424 (setq ret "Ok.")) ;init value
356 (let ((status (lm-verify f))) 425
357 (if status 426 (if (and file (file-directory-p file))
358 (progn 427 (setq
359 (insert f ":") 428 ret
360 (lm-insert-at-column lm-comment-column status "\n")) 429 (progn
361 (and showok 430 (switch-to-buffer (get-buffer-create "*lm-verify*"))
431 (erase-buffer)
432 (mapcar
433 '(lambda (f)
434 (if (string-match ".*\\.el$" f)
435 (let ((status (lm-verify f)))
436 (if status
362 (progn 437 (progn
363 (insert f ":") 438 (insert f ":")
364 (lm-insert-at-column lm-comment-column "OK\n"))))))) 439 (lm-insert-at-column lm-comment-column status "\n"))
365 (directory-files file)) 440 (and showok
366 ) 441 (progn
367 (save-excursion 442 (insert f ":")
368 (if file 443 (lm-insert-at-column lm-comment-column "OK\n")))))))
369 (find-file file)) 444 (directory-files file))
370 (prog1 445 ))
371 (cond 446 (save-excursion
372 ((not (lm-summary)) 447 (if file
373 "Can't find a package summary") 448 (find-file file))
374 ((not (lm-code-mark)) 449 (setq name (lm-get-package-name))
375 "Can't find a code section marker") 450
376 ((progn 451 (setq
377 (goto-char (point-max)) 452 ret
378 (forward-line -1) 453 (prog1
379 (looking-at (concat ";;; " file "ends here"))) 454 (cond
380 "Can't find a footer line") 455 ((null name)
381 ) 456 "Can't find a package NAME")
382 (if file 457
383 (kill-buffer (current-buffer))) 458 ((not (lm-authors))
384 )))) 459 "Author: tag missing.")
460
461 ((not (lm-maintainer))
462 "Maintainer: tag missing.")
463
464 ((not (lm-summary))
465 "Can't find a one-line 'Summary' description")
466
467 ((not (lm-keywords))
468 "Keywords: tag missing.")
469
470 ((not (lm-commentary-mark))
471 "Can't find a 'Commentary' section marker.")
472
473 ((not (lm-history-mark))
474 "Can't find a 'History' section marker.")
475
476 ((not (lm-code-mark))
477 "Can't find a 'Code' section marker")
478
479 ((progn
480 (goto-char (point-max))
481 (not
482 (re-search-backward
483 (concat "^;;;[ \t]+" name "[ \t]+ends here[ \t]*$"
484 "\\|^;;;[ \t]+ End of file[ \t]+" name)
485 nil t
486 )))
487 (format "Can't find a footer line for [%s]" name))
488 (t
489 ret))
490 (if file
491 (kill-buffer (current-buffer)))
492 ))))
493 (if verb
494 (message ret))
495 ret
496 ))
385 497
386(defun lm-synopsis (&optional file showall) 498(defun lm-synopsis (&optional file showall)
387 "Generate a synopsis listing for the buffer or the given FILE if given. 499 "Generate a synopsis listing for the buffer or the given FILE if given.
388If FILE is a directory, recurse on its files and generate a report into 500If FILE is a directory, recurse on its files and generate a report into
389a temporary buffer. If SHOWALL is on, also generate a line for files 501a temporary buffer. If SHOWALL is on, also generate a line for files
390which do not include a recognizable synopsis." 502which do not include a recognizable synopsis."
391 (interactive "fSynopsis for (file or dir): ") 503 (interactive
504 (list
505 (read-file-name "Synopsis for (file or dir): ")))
506
392 (if (and file (file-directory-p file)) 507 (if (and file (file-directory-p file))
393 (progn 508 (progn
394 (switch-to-buffer (get-buffer-create "*lm-verify*")) 509 (switch-to-buffer (get-buffer-create "*lm-verify*"))
@@ -420,9 +535,9 @@ which do not include a recognizable synopsis."
420 "Report a bug in the package currently being visited to its maintainer. 535 "Report a bug in the package currently being visited to its maintainer.
421Prompts for bug subject. Leaves you in a mail buffer." 536Prompts for bug subject. Leaves you in a mail buffer."
422 (interactive "sBug Subject: ") 537 (interactive "sBug Subject: ")
423 (let ((package (buffer-name)) 538 (let ((package (lm-get-package-name))
424 (addr (lm-maintainer)) 539 (addr (lm-maintainer))
425 (version (lm-version))) 540 (version (lm-version)))
426 (mail nil 541 (mail nil
427 (if addr 542 (if addr
428 (concat (car addr) " <" (cdr addr) ">") 543 (concat (car addr) " <" (cdr addr) ">")
@@ -433,9 +548,10 @@ Prompts for bug subject. Leaves you in a mail buffer."
433 package 548 package
434 (if version (concat " version " version) "") 549 (if version (concat " version " version) "")
435 "\n\n") 550 "\n\n")
436 (message "%s" 551 (message
437 (substitute-command-keys "Type \\[mail-send] to send bug report.")))) 552 (substitute-command-keys "Type \\[mail-send] to send bug report."))))
438 553
439(provide 'lisp-mnt) 554(provide 'lisp-mnt)
440 555
441;;; lisp-mnt.el ends here 556;;; lisp-mnt.el ends here
557