aboutsummaryrefslogtreecommitdiffstats
path: root/admin/admin.el
diff options
context:
space:
mode:
Diffstat (limited to 'admin/admin.el')
-rw-r--r--admin/admin.el542
1 files changed, 360 insertions, 182 deletions
diff --git a/admin/admin.el b/admin/admin.el
index e815dfade47..007cb06e592 100644
--- a/admin/admin.el
+++ b/admin/admin.el
@@ -1,6 +1,6 @@
1;;; admin.el --- utilities for Emacs administration 1;;; admin.el --- utilities for Emacs administration
2 2
3;; Copyright (C) 2001-2013 Free Software Foundation, Inc. 3;; Copyright (C) 2001-2014 Free Software Foundation, Inc.
4 4
5;; This file is part of GNU Emacs. 5;; This file is part of GNU Emacs.
6 6
@@ -21,46 +21,64 @@
21 21
22;; add-release-logs Add ``Version X released'' change log entries. 22;; add-release-logs Add ``Version X released'' change log entries.
23;; set-version Change Emacs version number in source tree. 23;; set-version Change Emacs version number in source tree.
24;; set-copyright Change emacs short copyright string (eg as 24;; set-copyright Change Emacs short copyright string (eg as
25;; printed by --version) in source tree. 25;; printed by --version) in source tree.
26 26
27;;; Code: 27;;; Code:
28 28
29(defvar add-log-time-format) ; in add-log 29(defvar add-log-time-format) ; in add-log
30 30
31(defun add-release-logs (root version) 31;; Does this information need to be in every ChangeLog, as opposed to
32;; just the top-level one? Only if you allow changes the same
33;; day as the release.
34;; http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00161.html
35(defun add-release-logs (root version &optional date)
32 "Add \"Version VERSION released.\" change log entries in ROOT. 36 "Add \"Version VERSION released.\" change log entries in ROOT.
33Root must be the root of an Emacs source tree." 37Root must be the root of an Emacs source tree.
34 (interactive "DEmacs root directory: \nNVersion number: ") 38Optional argument DATE is the release date, default today."
39 (interactive (list (read-directory-name "Emacs root directory: ")
40 (read-string "Version number: "
41 (format "%s.%s" emacs-major-version
42 emacs-minor-version))
43 (read-string "Release date: "
44 (progn (require 'add-log)
45 (let ((add-log-time-zone-rule t))
46 (funcall add-log-time-format))))))
35 (setq root (expand-file-name root)) 47 (setq root (expand-file-name root))
36 (unless (file-exists-p (expand-file-name "src/emacs.c" root)) 48 (unless (file-exists-p (expand-file-name "src/emacs.c" root))
37 (error "%s doesn't seem to be the root of an Emacs source tree" root)) 49 (user-error "%s doesn't seem to be the root of an Emacs source tree" root))
38 (require 'add-log) 50 (require 'add-log)
51 (or date (setq date (let ((add-log-time-zone-rule t))
52 (funcall add-log-time-format))))
39 (let* ((logs (process-lines "find" root "-name" "ChangeLog")) 53 (let* ((logs (process-lines "find" root "-name" "ChangeLog"))
40 (entry (format "%s %s <%s>\n\n\t* Version %s released.\n\n" 54 (entry (format "%s %s <%s>\n\n\t* Version %s released.\n\n"
41 (funcall add-log-time-format) 55 date
42 (or add-log-full-name (user-full-name)) 56 (or add-log-full-name (user-full-name))
43 (or add-log-mailing-address user-mail-address) 57 (or add-log-mailing-address user-mail-address)
44 version))) 58 version)))
45 (dolist (log logs) 59 (dolist (log logs)
46 (unless (string-match "/gnus/" log) 60 (find-file log)
47 (find-file log) 61 (goto-char (point-min))
48 (goto-char (point-min)) 62 (insert entry))))
49 (insert entry)))))
50 63
51(defun set-version-in-file (root file version rx) 64(defun set-version-in-file (root file version rx)
65 "Subroutine of `set-version' and `set-copyright'."
52 (find-file (expand-file-name file root)) 66 (find-file (expand-file-name file root))
53 (goto-char (point-min)) 67 (goto-char (point-min))
54 (unless (re-search-forward rx nil t) 68 (unless (re-search-forward rx nil :noerror)
55 (error "Version not found in %s" file)) 69 (user-error "Version not found in %s" file))
56 (replace-match (format "%s" version) nil nil nil 1)) 70 (replace-match (format "%s" version) nil nil nil 1))
57 71
72;; TODO report the progress
58(defun set-version (root version) 73(defun set-version (root version)
59 "Set Emacs version to VERSION in relevant files under ROOT. 74 "Set Emacs version to VERSION in relevant files under ROOT.
60Root must be the root of an Emacs source tree." 75Root must be the root of an Emacs source tree."
61 (interactive "DEmacs root directory: \nsVersion number: ") 76 (interactive "DEmacs root directory: \nsVersion number: ")
62 (unless (file-exists-p (expand-file-name "src/emacs.c" root)) 77 (unless (file-exists-p (expand-file-name "src/emacs.c" root))
63 (error "%s doesn't seem to be the root of an Emacs source tree" root)) 78 (user-error "%s doesn't seem to be the root of an Emacs source tree" root))
79 ;; There's also a "version 3" (standing for GPLv3) at the end of
80 ;; `README', but since `set-version-in-file' only replaces the first
81 ;; occurrence, it won't be replaced.
64 (set-version-in-file root "README" version 82 (set-version-in-file root "README" version
65 (rx (and "version" (1+ space) 83 (rx (and "version" (1+ space)
66 (submatch (1+ (in "0-9.")))))) 84 (submatch (1+ (in "0-9."))))))
@@ -91,7 +109,7 @@ Root must be the root of an Emacs source tree."
91 ;; in two places those commas are followed by space, in two other 109 ;; in two places those commas are followed by space, in two other
92 ;; places they are not. 110 ;; places they are not.
93 (let* ((version-components (append (split-string version "\\.") 111 (let* ((version-components (append (split-string version "\\.")
94 '("0" "0"))) 112 '("0" "0")))
95 (comma-version 113 (comma-version
96 (concat (car version-components) "," 114 (concat (car version-components) ","
97 (cadr version-components) "," 115 (cadr version-components) ","
@@ -144,6 +162,7 @@ Root must be the root of an Emacs source tree."
144 162
145 163
146;; Note this makes some assumptions about form of short copyright. 164;; Note this makes some assumptions about form of short copyright.
165;; TODO report the progress
147(defun set-copyright (root copyright) 166(defun set-copyright (root copyright)
148 "Set Emacs short copyright to COPYRIGHT in relevant files under ROOT. 167 "Set Emacs short copyright to COPYRIGHT in relevant files under ROOT.
149Root must be the root of an Emacs source tree." 168Root must be the root of an Emacs source tree."
@@ -154,7 +173,7 @@ Root must be the root of an Emacs source tree."
154 (format "Copyright (C) %s Free Software Foundation, Inc." 173 (format "Copyright (C) %s Free Software Foundation, Inc."
155 (format-time-string "%Y"))))) 174 (format-time-string "%Y")))))
156 (unless (file-exists-p (expand-file-name "src/emacs.c" root)) 175 (unless (file-exists-p (expand-file-name "src/emacs.c" root))
157 (error "%s doesn't seem to be the root of an Emacs source tree" root)) 176 (user-error "%s doesn't seem to be the root of an Emacs source tree" root))
158 (set-version-in-file root "configure.ac" copyright 177 (set-version-in-file root "configure.ac" copyright
159 (rx (and bol "copyright" (0+ (not (in ?\"))) 178 (rx (and bol "copyright" (0+ (not (in ?\")))
160 ?\" (submatch (1+ (not (in ?\")))) ?\"))) 179 ?\" (submatch (1+ (not (in ?\")))) ?\")))
@@ -180,54 +199,87 @@ Root must be the root of an Emacs source tree."
180 199
181;;; Various bits of magic for generating the web manuals 200;;; Various bits of magic for generating the web manuals
182 201
183(defun make-manuals (root) 202(defun manual-misc-manuals (root)
184 "Generate the web manuals for the Emacs webpage." 203 "Return doc/misc manuals as list of strings.
185 (interactive "DEmacs root directory: ") 204ROOT should be the root of an Emacs source tree."
205 ;; Similar to `make -C doc/misc echo-info', but works if unconfigured,
206 ;; and for INFO_TARGETS rather than INFO_INSTALL.
207 (with-temp-buffer
208 (insert-file-contents (expand-file-name "doc/misc/Makefile.in" root))
209 ;; Should really use expanded value of INFO_TARGETS.
210 (search-forward "INFO_COMMON = ")
211 (let ((start (point)))
212 (end-of-line)
213 (while (and (looking-back "\\\\")
214 (zerop (forward-line 1)))
215 (end-of-line))
216 (append (split-string (replace-regexp-in-string
217 "\\(\\\\\\|\\.info\\)" ""
218 (buffer-substring start (point))))
219 '("efaq-w32")))))
220
221;; TODO report the progress
222(defun make-manuals (root &optional type)
223 "Generate the web manuals for the Emacs webpage.
224ROOT should be the root of an Emacs source tree.
225Interactively with a prefix argument, prompt for TYPE.
226Optional argument TYPE is type of output (nil means all)."
227 (interactive (let ((root (read-directory-name "Emacs root directory: "
228 source-directory nil t)))
229 (list root
230 (if current-prefix-arg
231 (completing-read
232 "Type: "
233 (append
234 '("misc" "pdf" "ps")
235 (let (res)
236 (dolist (i '("emacs" "elisp" "eintr") res)
237 (dolist (j '("" "-mono" "-node" "-ps" "-pdf"))
238 (push (concat i j) res))))
239 (manual-misc-manuals root)))))))
186 (let* ((dest (expand-file-name "manual" root)) 240 (let* ((dest (expand-file-name "manual" root))
187 (html-node-dir (expand-file-name "html_node" dest)) 241 (html-node-dir (expand-file-name "html_node" dest))
188 (html-mono-dir (expand-file-name "html_mono" dest)) 242 (html-mono-dir (expand-file-name "html_mono" dest))
189 (txt-dir (expand-file-name "text" dest)) 243 (ps-dir (expand-file-name "ps" dest))
190 (dvi-dir (expand-file-name "dvi" dest)) 244 (pdf-dir (expand-file-name "pdf" dest))
191 (ps-dir (expand-file-name "ps" dest))) 245 (emacs (expand-file-name "doc/emacs/emacs.texi" root))
246 (elisp (expand-file-name "doc/lispref/elisp.texi" root))
247 (eintr (expand-file-name "doc/lispintro/emacs-lisp-intro.texi" root))
248 (misc (manual-misc-manuals root)))
249 ;; TODO this makes it non-continuable.
250 ;; Instead, delete the individual dest directory each time.
192 (when (file-directory-p dest) 251 (when (file-directory-p dest)
193 (if (y-or-n-p (format "Directory %s exists, delete it first?" dest)) 252 (if (y-or-n-p (format "Directory %s exists, delete it first? " dest))
194 (delete-directory dest t) 253 (delete-directory dest t)
195 (error "Aborted"))) 254 (user-error "Aborted")))
196 (make-directory dest) 255 (if (member type '(nil "emacs" "emacs-node"))
197 (make-directory html-node-dir) 256 (manual-html-node emacs (expand-file-name "emacs" html-node-dir)))
198 (make-directory html-mono-dir) 257 (if (member type '(nil "emacs" "emacs-mono"))
199 (make-directory txt-dir) 258 (manual-html-mono emacs (expand-file-name "emacs.html" html-mono-dir)))
200 (make-directory dvi-dir) 259 (if (member type '(nil "emacs" "emacs-pdf" "pdf"))
201 (make-directory ps-dir) 260 (manual-pdf emacs (expand-file-name "emacs.pdf" pdf-dir)))
202 ;; Emacs manual 261 (if (member type '(nil "emacs" "emacs-ps" "ps"))
203 (let ((texi (expand-file-name "doc/emacs/emacs.texi" root))) 262 (manual-ps emacs (expand-file-name "emacs.ps" ps-dir)))
204 (manual-html-node texi (expand-file-name "emacs" html-node-dir)) 263 (if (member type '(nil "elisp" "elisp-node"))
205 (manual-html-mono texi (expand-file-name "emacs.html" html-mono-dir)) 264 (manual-html-node elisp (expand-file-name "elisp" html-node-dir)))
206 (manual-txt texi (expand-file-name "emacs.txt" txt-dir)) 265 (if (member type '(nil "elisp" "elisp-mono"))
207 (manual-pdf texi (expand-file-name "emacs.pdf" dest)) 266 (manual-html-mono elisp (expand-file-name "elisp.html" html-mono-dir)))
208 (manual-dvi texi (expand-file-name "emacs.dvi" dvi-dir) 267 (if (member type '(nil "elisp" "elisp-pdf" "pdf"))
209 (expand-file-name "emacs.ps" ps-dir))) 268 (manual-pdf elisp (expand-file-name "elisp.pdf" pdf-dir)))
210 ;; Lisp manual 269 (if (member type '(nil "elisp" "elisp-ps" "ps"))
211 (let ((texi (expand-file-name "doc/lispref/elisp.texi" root))) 270 (manual-ps elisp (expand-file-name "elisp.ps" ps-dir)))
212 (manual-html-node texi (expand-file-name "elisp" html-node-dir)) 271 (if (member type '(nil "eintr" "eintr-node"))
213 (manual-html-mono texi (expand-file-name "elisp.html" html-mono-dir)) 272 (manual-html-node eintr (expand-file-name "eintr" html-node-dir)))
214 (manual-txt texi (expand-file-name "elisp.txt" txt-dir)) 273 (if (member type '(nil "eintr" "eintr-node"))
215 (manual-pdf texi (expand-file-name "elisp.pdf" dest)) 274 (manual-html-mono eintr (expand-file-name "eintr.html" html-mono-dir)))
216 (manual-dvi texi (expand-file-name "elisp.dvi" dvi-dir) 275 (if (member type '(nil "eintr" "eintr-pdf" "pdf"))
217 (expand-file-name "elisp.ps" ps-dir))) 276 (manual-pdf eintr (expand-file-name "eintr.pdf" pdf-dir)))
277 (if (member type '(nil "eintr" "eintr-ps" "ps"))
278 (manual-ps eintr (expand-file-name "eintr.ps" ps-dir)))
218 ;; Misc manuals 279 ;; Misc manuals
219 (let ((manuals '("ada-mode" "auth" "autotype" "calc" "cc-mode" 280 (dolist (manual misc)
220 "cl" "dbus" "dired-x" "ebrowse" "ede" "ediff" 281 (if (member type `(nil ,manual "misc"))
221 "edt" "eieio" "emacs-mime" "epa" "erc" "ert" 282 (manual-misc-html manual root html-node-dir html-mono-dir)))
222 "eshell" "eudc" "faq" "flymake" "forms"
223 "gnus" "emacs-gnutls" "idlwave" "info"
224 "mairix-el" "message" "mh-e" "newsticker"
225 "nxml-mode" "org" "pcl-cvs" "pgg" "rcirc"
226 "remember" "reftex" "sasl" "sc" "semantic"
227 "ses" "sieve" "smtpmail" "speedbar" "tramp"
228 "url" "vip" "viper" "widget" "woman")))
229 (dolist (manual manuals)
230 (manual-misc-html manual root html-node-dir html-mono-dir)))
231 (message "Manuals created in %s" dest))) 283 (message "Manuals created in %s" dest)))
232 284
233(defconst manual-doctype-string 285(defconst manual-doctype-string
@@ -242,10 +294,14 @@ Root must be the root of an Emacs source tree."
242<meta name=\"DC.title\" content=\"gnu.org\">\n\n") 294<meta name=\"DC.title\" content=\"gnu.org\">\n\n")
243 295
244(defconst manual-style-string "<style type=\"text/css\"> 296(defconst manual-style-string "<style type=\"text/css\">
245@import url('/style.css');\n</style>\n") 297@import url('/software/emacs/manual.css');\n</style>\n")
246 298
247(defun manual-misc-html (name root html-node-dir html-mono-dir) 299(defun manual-misc-html (name root html-node-dir html-mono-dir)
248 (let ((texi (expand-file-name (format "doc/misc/%s.texi" name) root))) 300 ;; Hack to deal with the cases where .texi creates a different .info.
301 ;; Blech. TODO Why not just rename the .texi (or .info) files?
302 (let* ((texiname (cond ((equal name "ccmode") "cc-mode")
303 (t name)))
304 (texi (expand-file-name (format "doc/misc/%s.texi" texiname) root)))
249 (manual-html-node texi (expand-file-name name html-node-dir)) 305 (manual-html-node texi (expand-file-name name html-node-dir))
250 (manual-html-mono texi (expand-file-name (concat name ".html") 306 (manual-html-mono texi (expand-file-name (concat name ".html")
251 html-mono-dir)))) 307 html-mono-dir))))
@@ -255,7 +311,13 @@ Root must be the root of an Emacs source tree."
255This function also edits the HTML files so that they validate as 311This function also edits the HTML files so that they validate as
256HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using 312HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using
257the @import directive." 313the @import directive."
314 (make-directory (or (file-name-directory dest) ".") t)
258 (call-process "makeinfo" nil nil nil 315 (call-process "makeinfo" nil nil nil
316 "-D" "WWW_GNU_ORG"
317 "-I" (expand-file-name "../emacs"
318 (file-name-directory texi-file))
319 "-I" (expand-file-name "../misc"
320 (file-name-directory texi-file))
259 "--html" "--no-split" texi-file "-o" dest) 321 "--html" "--no-split" texi-file "-o" dest)
260 (with-temp-buffer 322 (with-temp-buffer
261 (insert-file-contents dest) 323 (insert-file-contents dest)
@@ -266,6 +328,7 @@ the @import directive."
266 (manual-html-fix-node-div) 328 (manual-html-fix-node-div)
267 (goto-char (point-max)) 329 (goto-char (point-max))
268 (re-search-backward "</body>[\n \t]*</html>") 330 (re-search-backward "</body>[\n \t]*</html>")
331 ;; Close the div id="content" that fix-index-1 added.
269 (insert "</div>\n\n") 332 (insert "</div>\n\n")
270 (save-buffer))) 333 (save-buffer)))
271 334
@@ -275,8 +338,14 @@ This function also edits the HTML files so that they validate as
275HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using 338HTML 4.01 Transitional, and pulls in the gnu.org stylesheet using
276the @import directive." 339the @import directive."
277 (unless (file-exists-p texi-file) 340 (unless (file-exists-p texi-file)
278 (error "Manual file %s not found" texi-file)) 341 (user-error "Manual file %s not found" texi-file))
342 (make-directory dir t)
279 (call-process "makeinfo" nil nil nil 343 (call-process "makeinfo" nil nil nil
344 "-D" "WWW_GNU_ORG"
345 "-I" (expand-file-name "../emacs"
346 (file-name-directory texi-file))
347 "-I" (expand-file-name "../misc"
348 (file-name-directory texi-file))
280 "--html" texi-file "-o" dir) 349 "--html" texi-file "-o" dir)
281 ;; Loop through the node files, fixing them up. 350 ;; Loop through the node files, fixing them up.
282 (dolist (f (directory-files dir nil "\\.html\\'")) 351 (dolist (f (directory-files dir nil "\\.html\\'"))
@@ -300,143 +369,244 @@ the @import directive."
300 (manual-html-fix-index-2) 369 (manual-html-fix-index-2)
301 (if copyright-text 370 (if copyright-text
302 (insert copyright-text)) 371 (insert copyright-text))
372 ;; Close the div id="content" that fix-index-1 added.
303 (insert "\n</div>\n")) 373 (insert "\n</div>\n"))
304 ;; For normal nodes, give the header div a blue bg. 374 ;; For normal nodes, give the header div a blue bg.
305 (manual-html-fix-node-div)) 375 (manual-html-fix-node-div t))
306 (save-buffer)))))) 376 (save-buffer))))))
307 377
308(defun manual-txt (texi-file dest)
309 "Run Makeinfo on TEXI-FILE, emitting plaintext output to DEST."
310 (call-process "makeinfo" nil nil nil
311 "--plaintext" "--no-split" texi-file "-o" dest)
312 (shell-command (concat "gzip -c " dest " > " (concat dest ".gz"))))
313
314(defun manual-pdf (texi-file dest) 378(defun manual-pdf (texi-file dest)
315 "Run texi2pdf on TEXI-FILE, emitting plaintext output to DEST." 379 "Run texi2pdf on TEXI-FILE, emitting PDF output to DEST."
316 (call-process "texi2pdf" nil nil nil texi-file "-o" dest)) 380 (make-directory (or (file-name-directory dest) ".") t)
317 381 (let ((default-directory (file-name-directory texi-file)))
318(defun manual-dvi (texi-file dest ps-dest) 382 (call-process "texi2pdf" nil nil nil
319 "Run texi2dvi on TEXI-FILE, emitting dvi output to DEST. 383 "-I" "../emacs" "-I" "../misc"
320Also generate PostScript output in PS-DEST." 384 texi-file "-o" dest)))
321 (call-process "texi2dvi" nil nil nil texi-file "-o" dest) 385
322 (call-process "dvips" nil nil nil dest "-o" ps-dest) 386(defun manual-ps (texi-file dest)
323 (call-process "gzip" nil nil nil dest) 387 "Generate a PostScript version of TEXI-FILE as DEST."
324 (call-process "gzip" nil nil nil ps-dest)) 388 (make-directory (or (file-name-directory dest) ".") t)
389 (let ((dvi-dest (concat (file-name-sans-extension dest) ".dvi"))
390 (default-directory (file-name-directory texi-file)))
391 ;; FIXME: Use `texi2dvi --ps'? --xfq
392 (call-process "texi2dvi" nil nil nil
393 "-I" "../emacs" "-I" "../misc"
394 texi-file "-o" dvi-dest)
395 (call-process "dvips" nil nil nil dvi-dest "-o" dest)
396 (delete-file dvi-dest)
397 (call-process "gzip" nil nil nil dest)))
325 398
326(defun manual-html-fix-headers () 399(defun manual-html-fix-headers ()
327 "Fix up HTML headers for the Emacs manual in the current buffer." 400 "Fix up HTML headers for the Emacs manual in the current buffer."
328 (let (opoint) 401 (let ((texi5 (search-forward "<!DOCTYPE" nil t))
329 (insert manual-doctype-string) 402 opoint)
403 ;; Texinfo 5 supplies a DOCTYPE.
404 (or texi5
405 (insert manual-doctype-string))
330 (search-forward "<head>\n") 406 (search-forward "<head>\n")
331 (insert manual-meta-string) 407 (insert manual-meta-string)
332 (search-forward "<meta") 408 (search-forward "<meta")
333 (setq opoint (match-beginning 0)) 409 (setq opoint (match-beginning 0))
334 (re-search-forward "<!--") 410 (unless texi5
411 (search-forward "<!--")
412 (goto-char (match-beginning 0))
413 (delete-region opoint (point))
414 (search-forward "<meta http-equiv=\"Content-Style")
415 (setq opoint (match-beginning 0)))
416 (search-forward "</head>")
335 (goto-char (match-beginning 0)) 417 (goto-char (match-beginning 0))
336 (delete-region opoint (point)) 418 (delete-region opoint (point))
337 (insert manual-style-string) 419 (insert manual-style-string)
338 (search-forward "<meta http-equiv=\"Content-Style") 420 ;; Remove Texinfo 5 hard-coding bgcolor, text, link, vlink, alink.
339 (setq opoint (match-beginning 0)) 421 (when (re-search-forward "<body lang=\"[^\"]+\"" nil t)
340 (search-forward "</head>") 422 (setq opoint (point))
341 (delete-region opoint (match-beginning 0)))) 423 (search-forward ">")
424 (if (> (point) (1+ opoint))
425 (delete-region opoint (1- (point))))
426 (search-backward "</head"))))
342 427
343(defun manual-html-fix-node-div () 428;; Texinfo 5 changed these from class = "node" to "header", yay.
429(defun manual-html-fix-node-div (&optional split)
344 "Fix up HTML \"node\" divs in the current buffer." 430 "Fix up HTML \"node\" divs in the current buffer."
345 (let (opoint div-end) 431 (let (opoint div-end type)
346 (while (search-forward "<div class=\"node\">" nil t) 432 (while (re-search-forward "<div class=\"\\(node\\|header\\)\"\\(>\\)" nil t)
347 (replace-match 433 (setq type (match-string 1))
348 "<div class=\"node\" style=\"background-color:#DDDDFF\">" 434 ;; NB it is this that makes the bg of non-header cells in the
349 t t) 435 ;; index tables be blue. Is that intended?
436 ;; Also, if you don't remove the <hr>, the color of the first
437 ;; row in the table will be wrong.
438 ;; This all seems rather odd to me...
439 (replace-match " style=\"background-color:#DDDDFF\">" t t nil 2)
350 (setq opoint (point)) 440 (setq opoint (point))
351 (re-search-forward "</div>") 441 (when (or split (equal type "node"))
352 (setq div-end (match-beginning 0)) 442 ;; In Texinfo 4, the <hr> (and anchor) comes after the <div>.
353 (goto-char opoint) 443 (re-search-forward "</div>")
354 (if (search-forward "<hr>" div-end 'move) 444 (setq div-end (if (equal type "node")
355 (replace-match "" t t))))) 445 (match-beginning 0)
446 (line-end-position 2)))
447 (goto-char opoint)
448 (if (search-forward "<hr>" div-end 'move)
449 (replace-match "" t t)
450 (if split (forward-line -1))))
451 ;; In Texinfo 5, the <hr> (and anchor) comes before the <div> (?).
452 ;; Except in split output, where it comes on the line after
453 ;; the <div>. But only sometimes. I have no clue what the
454 ;; logic of where it goes is.
455 (when (equal type "header")
456 (goto-char opoint)
457 (when (re-search-backward "^<hr>$" (line-beginning-position -3) t)
458 (replace-match "")
459 (goto-char opoint))))))
460
356 461
357(defun manual-html-fix-index-1 () 462(defun manual-html-fix-index-1 ()
463 "Remove the h1 header, and the short and long contents lists.
464Also start a \"content\" div."
358 (let (opoint) 465 (let (opoint)
359 (re-search-forward "<body>\n") 466 (re-search-forward "<body.*>\n")
360 (setq opoint (match-end 0)) 467 (setq opoint (match-end 0))
361 (search-forward "<h2 class=\"") 468 ;; FIXME? Fragile if a Texinfo 5 document does not use @top.
469 (or (re-search-forward "<h1 class=\"top\"" nil t) ; Texinfo 5
470 (search-forward "<h2 class=\""))
362 (goto-char (match-beginning 0)) 471 (goto-char (match-beginning 0))
363 (delete-region opoint (point)) 472 (delete-region opoint (point))
473 ;; NB caller must close this div.
364 (insert "<div id=\"content\" class=\"inner\">\n\n"))) 474 (insert "<div id=\"content\" class=\"inner\">\n\n")))
365 475
366(defun manual-html-fix-index-2 (&optional table-workaround) 476(defun manual-html-fix-index-2 (&optional table-workaround)
367 "Replace the index list in the current buffer with a HTML table." 477 "Replace the index list in the current buffer with a HTML table.
368 (let (done open-td tag desc) 478Leave point after the table."
369 ;; Convert the list that Makeinfo made into a table. 479 (if (re-search-forward "<table class=\"menu\"\\(.*\\)>" nil t)
370 (or (search-forward "<ul class=\"menu\">" nil t) 480 ;; Texinfo 5 already uses a table. Tweak it a bit.
371 (search-forward "<ul>")) 481 (let (opoint done)
372 (replace-match "<table style=\"float:left\" width=\"100%\">") 482 (replace-match " style=\"float:left\" width=\"100%\"" nil t nil 1)
373 (forward-line 1) 483 (forward-line 1)
374 (while (not done) 484 (while (not done)
375 (cond 485 (cond ((re-search-forward "<tr><td.*&bull; \\(<a.*</a>\\)\
376 ((or (looking-at "<li>\\(<a.+</a>\\):[ \t]+\\(.*\\)$") 486:</td><td>&nbsp;&nbsp;</td><td[^>]*>\\(.*\\)" (line-end-position) t)
377 (looking-at "<li>\\(<a.+</a>\\)$")) 487 (replace-match (format "<tr><td%s>\\1</td>\n<td>\\2"
378 (setq tag (match-string 1)) 488 (if table-workaround
379 (setq desc (match-string 2)) 489 " bgcolor=\"white\"" "")))
380 (replace-match "" t t) 490 (search-forward "</td></tr>")
381 (when open-td 491 (forward-line 1))
382 (save-excursion 492 ((looking-at "<tr><th.*<pre class=\"menu-comment\">\n")
383 (forward-char -1) 493 (replace-match "<tr><th colspan=\"2\" align=\"left\" \
384 (skip-chars-backward " ") 494style=\"text-align:left\">")
385 (delete-region (point) (line-end-position)) 495 (search-forward "</pre></th></tr>")
386 (insert "</td>\n </tr>"))) 496 (replace-match "</th></tr>\n"))
387 (insert " <tr>\n ") 497 ;; Not all manuals have the detailed menu.
388 (if table-workaround 498 ;; If it is there, split it into a separate table.
389 ;; This works around a Firefox bug in the mono file. 499 ((re-search-forward "<tr>.*The Detailed Node Listing *"
390 (insert "<td bgcolor=\"white\">") 500 (line-end-position) t)
391 (insert "<td>")) 501 (setq opoint (match-beginning 0))
392 (insert tag "</td>\n <td>" (or desc "")) 502 (while (and (looking-at " *&mdash;")
393 (setq open-td t)) 503 (zerop (forward-line 1))))
394 ((eq (char-after) ?\n) 504 (delete-region opoint (point))
395 (delete-char 1) 505 (insert "</table>\n\n\
396 ;; Negate the following `forward-line'. 506<h2>Detailed Node Listing</h2>\n\n<p>")
397 (forward-line -1)) 507 ;; FIXME Fragile!
398 ((looking-at "<!-- ") 508 ;; The Emacs and Elisp manual have some text at the
399 (search-forward "-->")) 509 ;; start of the detailed menu that is not part of the menu.
400 ((looking-at "<p>[- ]*The Detailed Node Listing[- \n]*") 510 ;; Other manuals do not.
401 (replace-match " </td></tr></table>\n 511 (if (re-search-forward "in one step:" (line-end-position 3) t)
512 (forward-line 1))
513 (insert "</p>\n")
514 (search-forward "</pre></th></tr>")
515 (delete-region (match-beginning 0) (match-end 0))
516 (forward-line -1)
517 (or (looking-at "^$") (error "Parse error 1"))
518 (forward-line -1)
519 (if (looking-at "^$") (error "Parse error 2"))
520 (forward-line -1)
521 (or (looking-at "^$") (error "Parse error 3"))
522 (forward-line 1)
523 (insert "<table class=\"menu\" style=\"float:left\" width=\"100%\">\n\
524<tr><th colspan=\"2\" align=\"left\" style=\"text-align:left\">\n")
525 (forward-line 1)
526 (insert "</th></tr>")
527 (forward-line 1))
528 ((looking-at ".*</table")
529 (forward-line 1)
530 (setq done t)))))
531 (let (done open-td tag desc)
532 ;; Convert the list that Makeinfo made into a table.
533 (or (search-forward "<ul class=\"menu\">" nil t)
534 ;; FIXME? The following search seems dangerously lax.
535 (search-forward "<ul>"))
536 (replace-match "<table style=\"float:left\" width=\"100%\">")
537 (forward-line 1)
538 (while (not done)
539 (cond
540 ((or (looking-at "<li>\\(<a.+</a>\\):[ \t]+\\(.*\\)$")
541 (looking-at "<li>\\(<a.+</a>\\)$"))
542 (setq tag (match-string 1))
543 (setq desc (match-string 2))
544 (replace-match "" t t)
545 (when open-td
546 (save-excursion
547 (forward-char -1)
548 (skip-chars-backward " ")
549 (delete-region (point) (line-end-position))
550 (insert "</td>\n </tr>")))
551 (insert " <tr>\n ")
552 (if table-workaround
553 ;; This works around a Firefox bug in the mono file.
554 (insert "<td bgcolor=\"white\">")
555 (insert "<td>"))
556 (insert tag "</td>\n <td>" (or desc ""))
557 (setq open-td t))
558 ((eq (char-after) ?\n)
559 (delete-char 1)
560 ;; Negate the following `forward-line'.
561 (forward-line -1))
562 ((looking-at "<!-- ")
563 (search-forward "-->"))
564 ((looking-at "<p>[- ]*The Detailed Node Listing[- \n]*")
565 (replace-match " </td></tr></table>\n
402<h3>Detailed Node Listing</h3>\n\n" t t) 566<h3>Detailed Node Listing</h3>\n\n" t t)
403 (search-forward "<p>") 567 (search-forward "<p>")
404 (search-forward "<p>" nil t) 568 ;; FIXME Fragile!
405 (goto-char (match-beginning 0)) 569 ;; The Emacs and Elisp manual have some text at the
406 (skip-chars-backward "\n ") 570 ;; start of the detailed menu that is not part of the menu.
407 (setq open-td nil) 571 ;; Other manuals do not.
408 (insert "</p>\n\n<table style=\"float:left\" width=\"100%\">")) 572 (if (looking-at "Here are some other nodes")
409 ((looking-at "</li></ul>") 573 (search-forward "<p>"))
410 (replace-match "" t t)) 574 (goto-char (match-beginning 0))
411 ((looking-at "<p>") 575 (skip-chars-backward "\n ")
412 (replace-match "" t t) 576 (setq open-td nil)
413 (when open-td 577 (insert "</p>\n\n<table style=\"float:left\" width=\"100%\">"))
414 (insert " </td></tr>") 578 ((looking-at "</li></ul>")
415 (setq open-td nil)) 579 (replace-match "" t t))
416 (insert " <tr> 580 ((looking-at "<p>")
581 (replace-match "" t t)
582 (when open-td
583 (insert " </td></tr>")
584 (setq open-td nil))
585 (insert " <tr>
417 <th colspan=\"2\" align=\"left\" style=\"text-align:left\">") 586 <th colspan=\"2\" align=\"left\" style=\"text-align:left\">")
418 (if (re-search-forward "</p>[ \t\n]*<ul class=\"menu\">" nil t) 587 (if (re-search-forward "</p>[ \t\n]*<ul class=\"menu\">" nil t)
419 (replace-match " </th></tr>"))) 588 (replace-match " </th></tr>")))
420 ((looking-at "[ \t]*</ul>[ \t]*$") 589 ((looking-at "[ \t]*</ul>[ \t]*$")
421 (replace-match 590 (replace-match
422 (if open-td 591 (if open-td
423 " </td></tr>\n</table>" 592 " </td></tr>\n</table>"
424 "</table>") t t) 593 "</table>") t t)
425 (setq done t)) 594 (setq done t))
426 (t 595 (t
427 (if (eobp) 596 (if (eobp)
428 (error "Parse error in %s" f)) ; f is bound in manual-html-node 597 (error "Parse error in %s"
429 (unless open-td 598 (file-name-nondirectory buffer-file-name)))
430 (setq done t)))) 599 (unless open-td
431 (forward-line 1)))) 600 (setq done t))))
601 (forward-line 1)))))
432 602
433 603
434;; Stuff to check new defcustoms got :version tags. 604;; Stuff to check new `defcustom's got :version tags.
435;; Adapted from check-declare.el. 605;; Adapted from check-declare.el.
436 606
437(defun cusver-find-files (root &optional old) 607(defun cusver-find-files (root &optional old)
438 "Find .el files beneath directory ROOT that contain defcustoms. 608 "Find .el files beneath directory ROOT that contain `defcustom's.
439If optional OLD is non-nil, also include defvars." 609If optional OLD is non-nil, also include `defvar's."
440 (process-lines find-program root 610 (process-lines find-program root
441 "-name" "*.el" 611 "-name" "*.el"
442 "-exec" grep-program 612 "-exec" grep-program
@@ -448,14 +618,14 @@ If optional OLD is non-nil, also include defvars."
448 618
449(defvar cusver-new-version (format "%s.%s" emacs-major-version 619(defvar cusver-new-version (format "%s.%s" emacs-major-version
450 (1+ emacs-minor-version)) 620 (1+ emacs-minor-version))
451 "Version number that new defcustoms should have.") 621 "Version number that new `defcustom's should have.")
452 622
453(defun cusver-scan (file &optional old) 623(defun cusver-scan (file &optional old)
454 "Scan FILE for `defcustom' calls. 624 "Scan FILE for `defcustom' calls.
455Return a list with elements of the form (VAR . VER), 625Return a list with elements of the form (VAR . VER),
456This means that FILE contains a defcustom for variable VAR, with 626This means that FILE contains a defcustom for variable VAR, with
457a :version tag having value VER (may be nil). 627a :version tag having value VER (may be nil).
458If optional argument OLD is non-nil, also scan for defvars." 628If optional argument OLD is non-nil, also scan for `defvar's."
459 (let ((m (format "Scanning %s..." file)) 629 (let ((m (format "Scanning %s..." file))
460 (re (format "^[ \t]*\\((def%s\\)[ \t\n]" 630 (re (format "^[ \t]*\\((def%s\\)[ \t\n]"
461 (if old "\\(custom\\|var\\)" "\\(custom\\|group\\)"))) 631 (if old "\\(custom\\|var\\)" "\\(custom\\|group\\)")))
@@ -464,13 +634,19 @@ If optional argument OLD is non-nil, also scan for defvars."
464 (with-temp-buffer 634 (with-temp-buffer
465 (insert-file-contents file) 635 (insert-file-contents file)
466 ;; FIXME we could theoretically be inside a string. 636 ;; FIXME we could theoretically be inside a string.
467 (while (re-search-forward re nil t) 637 (while (re-search-forward re nil :noerror)
468 (goto-char (match-beginning 1)) 638 (goto-char (match-beginning 1))
469 (if (and (setq form (ignore-errors (read (current-buffer)))) 639 (if (and (setq form (ignore-errors (read (current-buffer))))
470 (setq var (car-safe (cdr-safe form))) 640 (setq var (car-safe (cdr-safe form)))
471 ;; Exclude macros, eg (defcustom ,varname ...). 641 ;; Exclude macros, eg (defcustom ,varname ...).
472 (symbolp var)) 642 (symbolp var))
473 (progn 643 (progn
644 ;; FIXME It should be cus-test-apropos that does this.
645 (and (not old)
646 (equal "custom" (match-string 2))
647 (not (memq :type form))
648 (display-warning 'custom
649 (format "Missing type in: `%s'" form)))
474 (setq ver (car (cdr-safe (memq :version form)))) 650 (setq ver (car (cdr-safe (memq :version form))))
475 (if (equal "group" (match-string 2)) 651 (if (equal "group" (match-string 2))
476 ;; Group :version could be old. 652 ;; Group :version could be old.
@@ -506,7 +682,7 @@ If optional argument OLD is non-nil, also scan for defvars."
506(define-button-type 'cusver-xref 'action #'cusver-goto-xref) 682(define-button-type 'cusver-xref 'action #'cusver-goto-xref)
507 683
508(defun cusver-goto-xref (button) 684(defun cusver-goto-xref (button)
509 "Jump to a lisp file for the BUTTON at point." 685 "Jump to a Lisp file for the BUTTON at point."
510 (let ((file (button-get button 'file)) 686 (let ((file (button-get button 'file))
511 (var (button-get button 'var))) 687 (var (button-get button 'var)))
512 (if (not (file-readable-p file)) 688 (if (not (file-readable-p file))
@@ -522,34 +698,36 @@ If optional argument OLD is non-nil, also scan for defvars."
522;; TODO Check cus-start if something moved from C to Lisp. 698;; TODO Check cus-start if something moved from C to Lisp.
523;; TODO Handle renamed things with aliases to the old names. 699;; TODO Handle renamed things with aliases to the old names.
524(defun cusver-check (newdir olddir version) 700(defun cusver-check (newdir olddir version)
525 "Check that defcustoms have :version tags where needed. 701 "Check that `defcustom's have :version tags where needed.
526NEWDIR is the current lisp/ directory, OLDDIR is that from the previous 702NEWDIR is the current lisp/ directory, OLDDIR is that from the
527release. A defcustom that is only in NEWDIR should have a :version 703previous release, VERSION is the new version number. A
528tag. We exclude cases where a defvar exists in OLDDIR, since 704`defcustom' that is only in NEWDIR should have a :version tag.
529just converting a defvar to a defcustom does not require a :version bump. 705We exclude cases where a `defvar' exists in OLDDIR, since just
706converting a `defvar' to a `defcustom' does not require
707a :version bump.
530 708
531Note that a :version tag should also be added if the value of a defcustom 709Note that a :version tag should also be added if the value of a defcustom
532changes (in a non-trivial way). This function does not check for that." 710changes (in a non-trivial way). This function does not check for that."
533 (interactive (list (read-directory-name "New Lisp directory: ") 711 (interactive (list (read-directory-name "New Lisp directory: " nil nil t)
534 (read-directory-name "Old Lisp directory: ") 712 (read-directory-name "Old Lisp directory: " nil nil t)
535 (number-to-string 713 (number-to-string
536 (read-number "New version number: " 714 (read-number "New version number: "
537 (string-to-number cusver-new-version))))) 715 (string-to-number cusver-new-version)))))
538 (or (file-directory-p (setq newdir (expand-file-name newdir))) 716 (or (file-directory-p (setq newdir (expand-file-name newdir)))
539 (error "Directory `%s' not found" newdir)) 717 (user-error "Directory `%s' not found" newdir))
540 (or (file-directory-p (setq olddir (expand-file-name olddir))) 718 (or (file-directory-p (setq olddir (expand-file-name olddir)))
541 (error "Directory `%s' not found" olddir)) 719 (user-error "Directory `%s' not found" olddir))
542 (setq cusver-new-version version) 720 (setq cusver-new-version version)
543 (let* ((newfiles (progn (message "Finding new files with defcustoms...") 721 (let* ((newfiles (progn (message "Finding new files with `defcustom's...")
544 (cusver-find-files newdir))) 722 (cusver-find-files newdir)))
545 (oldfiles (progn (message "Finding old files with defcustoms...") 723 (oldfiles (progn (message "Finding old files with `defcustom's...")
546 (cusver-find-files olddir t))) 724 (cusver-find-files olddir t)))
547 (newcus (progn (message "Reading new defcustoms...") 725 (newcus (progn (message "Reading new `defcustom's...")
548 (mapcar 726 (mapcar
549 (lambda (file) 727 (lambda (file)
550 (cons file (cusver-scan file))) newfiles))) 728 (cons file (cusver-scan file))) newfiles)))
551 oldcus result thisfile file) 729 oldcus result thisfile file)
552 (message "Reading old defcustoms...") 730 (message "Reading old `defcustom's...")
553 (dolist (file oldfiles) 731 (dolist (file oldfiles)
554 (setq oldcus (append oldcus (cusver-scan file t)))) 732 (setq oldcus (append oldcus (cusver-scan file t))))
555 (setq oldcus (append oldcus (cusver-scan-cus-start 733 (setq oldcus (append oldcus (cusver-scan-cus-start
@@ -574,7 +752,7 @@ changes (in a non-trivial way). This function does not check for that."
574 (message "No missing :version tags") 752 (message "No missing :version tags")
575 (pop-to-buffer "*cusver*") 753 (pop-to-buffer "*cusver*")
576 (erase-buffer) 754 (erase-buffer)
577 (insert "These defcustoms might be missing :version tags:\n\n") 755 (insert "These `defcustom's might be missing :version tags:\n\n")
578 (dolist (elem result) 756 (dolist (elem result)
579 (let* ((str (file-relative-name (car elem) newdir)) 757 (let* ((str (file-relative-name (car elem) newdir))
580 (strlen (length str))) 758 (strlen (length str)))