comparison lisp/info.el @ 274:ca9a9ec9c1c1 r21-0b35

Import from CVS: tag r21-0b35
author cvs
date Mon, 13 Aug 2007 10:29:42 +0200
parents c5d627a313b1
children 90d73dddcdc4
comparison
equal deleted inserted replaced
273:411aac7253ef 274:ca9a9ec9c1c1
385 file. An example might be something like: 385 file. An example might be something like:
386 \"/usr/local/lib/xemacs/packages/lisp/calc/\"" 386 \"/usr/local/lib/xemacs/packages/lisp/calc/\""
387 :type '(repeat directory) 387 :type '(repeat directory)
388 :group 'info) 388 :group 'info)
389 389
390 (defcustom Info-rebuild-outdated-dir 'ask 390 (defcustom Info-rebuild-outdated-dir 'conservative
391 "*What to do if the `dir' or `localdir' file needs to be (re)built. 391 "*What to do if the `dir' or `localdir' file needs to be (re)built.
392 Possible values are: 392 Possible values are:
393 `never' never (re)build the `dir' or `localdir' file 393 `never' never (re)build the `dir' or `localdir' file
394 `always' automatically (re)builds when needed 394 `always' automatically (re)builds when needed
395 `ask' asks the user before (re)building" 395 `ask' asks the user before (re)building
396 `conservative' asks the user before overwriting existing files"
396 :type '(choice (const :tag "never" never) 397 :type '(choice (const :tag "never" never)
397 (const :tag "always" always) 398 (const :tag "always" always)
398 (const :tag "ask" ask)) 399 (const :tag "ask" ask)
400 (const :tag "conservative" conservative))
399 :group 'info) 401 :group 'info)
400 402
401 (defvar Info-emacs-info-file-name "xemacs.info" 403 (defvar Info-emacs-info-file-name "xemacs.info"
402 "The filename of the XEmacs info for 404 "The filename of the XEmacs info for
403 `Info-goto-emacs-command-node' (`\\<help-mode-map>\\[Info-goto-emacs-command-node]')") 405 `Info-goto-emacs-command-node' (`\\<help-mode-map>\\[Info-goto-emacs-command-node]')")
499 This (the Directory node) gives a menu of major topics. 501 This (the Directory node) gives a menu of major topics.
500 502
501 * Menu: The list of major topics begins on the next line. 503 * Menu: The list of major topics begins on the next line.
502 504
503 ") 505 ")
506
507 (defvar Info-no-description-string "[No description available]"
508 "Description string for info files that have none")
504 509
505 ;;;###autoload 510 ;;;###autoload
506 (defun info (&optional file) 511 (defun info (&optional file)
507 "Enter Info, the documentation browser. 512 "Enter Info, the documentation browser.
508 Optional argument FILE specifies the file to examine; 513 Optional argument FILE specifies the file to examine;
812 ))) 817 )))
813 (setq dirs-done 818 (setq dirs-done
814 (cons truename 819 (cons truename
815 (cons (directory-file-name truename) 820 (cons (directory-file-name truename)
816 dirs-done))) 821 dirs-done)))
817 (if (not (string= truename 822 (Info-maybe-update-dir file)
818 (file-truename (car Info-directory-list))))
819 (Info-maybe-update-dir file))
820 (setq attrs (file-attributes file)) 823 (setq attrs (file-attributes file))
821 (if (or (setq buf (find-buffer-visiting file)) 824 (if (or (setq buf (find-buffer-visiting file))
822 attrs) 825 attrs)
823 (save-excursion 826 (save-excursion
824 (or buffers 827 (or buffers
831 (if (not buf) 834 (if (not buf)
832 (insert-file-contents file)) 835 (insert-file-contents file))
833 (if (string-match "localdir" (buffer-name)) 836 (if (string-match "localdir" (buffer-name))
834 (setq lbuffers (cons (current-buffer) lbuffers)) 837 (setq lbuffers (cons (current-buffer) lbuffers))
835 (setq buffers (cons (current-buffer) buffers))) 838 (setq buffers (cons (current-buffer) buffers)))
836 (setq Info-dir-file-attributes 839 (if attrs
837 (cons (cons file attrs) 840 (setq Info-dir-file-attributes
838 Info-dir-file-attributes)))))) 841 (cons (cons file attrs)
842 Info-dir-file-attributes)))))))
839 (or (cdr dirs) (setq Info-dir-contents-directory (car dirs))) 843 (or (cdr dirs) (setq Info-dir-contents-directory (car dirs)))
840 (setq dirs (cdr dirs)))) 844 (setq dirs (cdr dirs))))
841 845
842 ;; ensure that the localdir files are inserted last, and reverse 846 ;; ensure that the localdir files are inserted last, and reverse
843 ;; the list of them so that when they get pushed in, they appear 847 ;; the list of them so that when they get pushed in, they appear
972 (not (file-exists-p (file-name-directory file))) 976 (not (file-exists-p (file-name-directory file)))
973 (null (directory-files (file-name-directory file) nil "\\.info"))) 977 (null (directory-files (file-name-directory file) nil "\\.info")))
974 (if (not (find-buffer-visiting file)) 978 (if (not (find-buffer-visiting file))
975 (if (not (file-exists-p file)) 979 (if (not (file-exists-p file))
976 (if (or (eq Info-rebuild-outdated-dir 'always) 980 (if (or (eq Info-rebuild-outdated-dir 'always)
981 (and (eq Info-rebuild-outdated-dir 'conservative)
982 (not (file-writable-p file)))
977 (and (eq Info-rebuild-outdated-dir 'ask) 983 (and (eq Info-rebuild-outdated-dir 'ask)
978 (y-or-n-p (format "No dir file in %s. Rebuild now ? " (file-name-directory file))))) 984 (y-or-n-p (format "No dir file in %s. Rebuild now ? " (file-name-directory file)))))
979 (Info-build-dir-anew (file-name-directory file) (not (file-writable-p file)))) 985 (Info-build-dir-anew (file-name-directory file) (not (file-writable-p file))))
980 (if (Info-dir-outdated-p file) 986 (if (Info-dir-outdated-p file)
981 (if (or (eq Info-rebuild-outdated-dir 'always) 987 (if (or (eq Info-rebuild-outdated-dir 'always)
988 (and (eq Info-rebuild-outdated-dir 'conservative)
989 (not (file-writable-p file)))
982 (and (eq Info-rebuild-outdated-dir 'ask) 990 (and (eq Info-rebuild-outdated-dir 'ask)
983 (y-or-n-p (format "%s is outdated. Rebuild now ? " file)))) 991 (y-or-n-p (format "%s is outdated. Rebuild now ? " file))))
984 (Info-rebuild-dir file (not (file-writable-p file))))))))) 992 (Info-rebuild-dir file (not (file-writable-p file)))))))))
985 993
986 ;; Record which *.info files are newer than the dir file 994 ;; Record which *.info files are newer than the dir file
987 (defvar Info-dir-newer-info-files nil) 995 (defvar Info-dir-newer-info-files nil)
988 996
989 (defun Info-dir-outdated-p (file) 997 (defun Info-dir-outdated-p (file)
990 "Return non-nil if dir or localdir is outdated. 998 "Return non-nil if dir or localdir is outdated.
991 dir or localdir are outdated when an *.info file in the same 999 dir or localdir are outdated when a *.info file in the same
992 directory has been modified more recently." 1000 directory has been modified more recently."
993 (let ((dir-mod-time (nth 5 (file-attributes file))) 1001 (let ((dir-mod-time (nth 5 (file-attributes file)))
994 f-mod-time 1002 f-mod-time
995 newer) 1003 newer)
996 (setq Info-dir-newer-info-files nil) 1004 (setq Info-dir-newer-info-files nil)
1010 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$" 1018 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$"
1011 'nosort 1019 'nosort
1012 t)) 1020 t))
1013 Info-dir-newer-info-files)) 1021 Info-dir-newer-info-files))
1014 1022
1015 (defun Info-extract-dir-entries-from (file) 1023 (defun Info-extract-dir-entry-from (file)
1016 "Extract dir entries from the info FILE. 1024 "Extract the dir entry from the info FILE.
1017 dir entries are delimited by the markers `START-INFO-DIR-ENTRY' 1025 The dir entry is delimited by the markers `START-INFO-DIR-ENTRY'
1018 and `END-INFO-DIR-ENTRY'" 1026 and `END-INFO-DIR-ENTRY'"
1019 (save-excursion 1027 (save-excursion
1020 (set-buffer (get-buffer-create " *Info-tmp*")) 1028 (set-buffer (get-buffer-create " *Info-tmp*"))
1021 (when (file-readable-p file) 1029 (when (file-readable-p file)
1022 (insert-file-contents file nil nil nil t) 1030 (insert-file-contents file nil nil nil t)
1025 (unless (null (re-search-forward "^START-INFO-DIR-ENTRY" nil t)) 1033 (unless (null (re-search-forward "^START-INFO-DIR-ENTRY" nil t))
1026 (forward-line 1) 1034 (forward-line 1)
1027 (setq beg (point)) 1035 (setq beg (point))
1028 (unless (null (re-search-forward "^END-INFO-DIR-ENTRY" nil t)) 1036 (unless (null (re-search-forward "^END-INFO-DIR-ENTRY" nil t))
1029 (goto-char (match-beginning 0)) 1037 (goto-char (match-beginning 0))
1030 (buffer-substring beg (point)))))))) 1038 (car (Info-parse-dir-entries beg (point)))))))))
1039
1040 ;; Parse dir entries contained between BEG and END into a list of the form
1041 ;; (filename topic node (description-line-1 description-line-2 ...))
1042 (defun Info-parse-dir-entries (beg end)
1043 (let (entry entries)
1044 (save-excursion
1045 (save-restriction
1046 (narrow-to-region beg end)
1047 (goto-char beg)
1048 (while (re-search-forward "^\\* \\([^:]+\\):\\([ \t]*(\\(.*\\))\\w*\\.\\|:\\)" nil t)
1049 (setq entry (list (match-string 2)
1050 (match-string 1)
1051 (downcase (or (match-string 3)
1052 (match-string 1)))))
1053 (setq entry (cons (nreverse
1054 (cdr
1055 (nreverse
1056 (split-string (buffer-substring (re-search-forward "[ \t]*" nil t)
1057 (or (and (re-search-forward "^[^ \t]" nil t)
1058 (goto-char (match-beginning 0)))
1059 (point-max)))
1060 "[ \t]*\n[ \t]*"))))
1061 entry))
1062 (setq entries (cons (nreverse entry) entries)))))
1063 (nreverse entries)))
1064
1065 (defun Info-dump-dir-entries (entries)
1066 (let ((tab-width 8)
1067 (description-col 0)
1068 len)
1069 (mapcar '(lambda (e)
1070 (setq e (cdr e)) ; Drop filename
1071 (setq len (length (concat (car e)
1072 (car (cdr e)))))
1073 (if (> len description-col)
1074 (setq description-col len)))
1075 entries)
1076 (setq description-col (+ 5 description-col))
1077 (mapcar '(lambda (e)
1078 (setq e (cdr e)) ; Drop filename
1079 (insert "* " (car e) ":" (car (cdr e)))
1080 (setq e (car (cdr (cdr e))))
1081 (while e
1082 (indent-to-column description-col)
1083 (insert (car e) "\n")
1084 (setq e (cdr e))))
1085 entries)))
1086
1031 1087
1032 (defun Info-build-dir-anew (directory to-temp) 1088 (defun Info-build-dir-anew (directory to-temp)
1033 "Build a new info dir file in DIRECTORY" 1089 "Build a new info dir file in DIRECTORY"
1034 (save-excursion 1090 (save-excursion
1035 (let ((dirfile (expand-file-name "dir" directory))) 1091 (let ((dirfile (expand-file-name "dir" directory))
1092 (info-files
1093 (directory-files directory
1094 'fullname
1095 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$"
1096 nil
1097 t)))
1036 (if to-temp 1098 (if to-temp
1037 (message "Creating temporary dir...") 1099 (display-warning 'info (format "Missing info dir file in %s" directory) 'notice)
1038 (message "Creating %s..." dirfile)) 1100 (message "Creating %s..." dirfile))
1039 (set-buffer (find-file-noselect dirfile)) 1101 (set-buffer (find-file-noselect dirfile t))
1102 (setq buffer-read-only nil)
1040 (erase-buffer) 1103 (erase-buffer)
1041 (insert Info-dir-prologue 1104 (insert Info-dir-prologue
1042 "Info files in " directory "\n\n") 1105 "Info files in " directory ":\n\n")
1043 (mapcar 1106 (Info-dump-dir-entries
1044 '(lambda (f) 1107 (mapcar
1045 (insert (or (Info-extract-dir-entries-from f) 1108 '(lambda (f)
1046 (format "* %s::\t[No description available]\n" 1109 (or (Info-extract-dir-entry-from f)
1047 (file-name-sans-extension (file-name-nondirectory f)))))) 1110 (list 'dummy
1048 (directory-files directory 1111 (file-name-sans-extension (file-name-nondirectory f))
1049 'fullname 1112 ":"
1050 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$" 1113 (list Info-no-description-string))))
1051 nil 1114 info-files))
1052 t))
1053 (if to-temp 1115 (if to-temp
1054 (set-buffer-modified-p nil) 1116 (set-buffer-modified-p nil)
1055 (save-buffer)) 1117 (save-buffer))
1056 (if to-temp 1118 (if to-temp
1057 (message "Creating temporary dir...done") 1119 (message "Creating temporary dir...done")
1058 (message "Creating %s...done" dirfile))))) 1120 (message "Creating %s...done" dirfile)))))
1059 1121
1060 (defvar Info-dir-entry-matcher "^\\* \\([^:]+\\):\\([ \t]*(\\(.*\\))\\w*\\.\\|:\\)[ \t]+\\(.*\\)$")
1061
1062 (defun Info-parse-dir-entry (entry)
1063 (string-match Info-dir-entry-matcher entry)
1064 (list (match-string 1 entry) (match-string 2 entry) (match-string 4 entry)))
1065 1122
1066 (defun Info-rebuild-dir (file to-temp) 1123 (defun Info-rebuild-dir (file to-temp)
1067 "Update an existing info dir file after info files have been modified" 1124 "Update an existing info dir file after info files have been modified"
1068 (save-excursion 1125 (save-excursion
1069 (let (dir-contents 1126 (save-restriction
1070 dir-entry 1127 (let (dir-section-contents dir-full-contents
1071 file-dir-entry) 1128 dir-entry
1072 (set-buffer (find-file-noselect file)) 1129 file-dir-entry
1073 (if to-temp 1130 mark next-section
1074 (message "Rebuilding temporary dir...") 1131 not-first-section)
1075 (message "Rebuilding %s..." file)) 1132 (set-buffer (find-file-noselect file t))
1076 (setq buffer-read-only nil) 1133 (setq buffer-read-only nil)
1077 (goto-char (point-min)) 1134 (if to-temp
1078 (search-forward "\^_") 1135 (display-warning 'info (format "Outdated info dir file: %s" file) 'notice)
1079 (re-search-forward "^\\* Menu:.*$" nil t) 1136 (message "Rebuilding %s..." file))
1080 (narrow-to-region (or (and (re-search-forward Info-dir-entry-matcher nil t) 1137 (catch 'done
1081 (match-beginning 0)) 1138 (setq buffer-read-only nil)
1082 (point)) 1139 (goto-char (point-min))
1083 (point-max)) 1140 (unless (and (search-forward "\^_")
1084 (goto-char (point-min)) 1141 (re-search-forward "^\\* Menu:.*$" nil t)
1085 (while (re-search-forward Info-dir-entry-matcher nil t) 1142 (setq mark (and (re-search-forward "^\\* " nil t)
1086 (setq dir-contents (cons (list (downcase (or (match-string 3) 1143 (match-beginning 0))))
1087 (match-string 1))) 1144 (throw 'done nil))
1088 (match-string 1) 1145 (setq dir-full-contents (Info-parse-dir-entries mark (point-max)))
1089 (match-string 2) 1146 (setq next-section (or (and (re-search-forward "^[^* \t].*:[ \t]*$" nil t)
1090 (match-string 4)) 1147 (match-beginning 0))
1091 dir-contents))) 1148 (point-max)))
1092 (mapcar '(lambda (file) 1149 (while next-section
1093 (setq dir-entry (assoc (downcase 1150 (narrow-to-region mark next-section)
1151 (setq dir-section-contents (nreverse (Info-parse-dir-entries (point-min)
1152 (point-max))))
1153 (mapcar '(lambda (file)
1154 (setq dir-entry (assoc (downcase
1155 (file-name-sans-extension
1156 (file-name-nondirectory file)))
1157 dir-section-contents)
1158 file-dir-entry (Info-extract-dir-entry-from file))
1159 (if dir-entry
1160 (if file-dir-entry
1161 ;; A dir entry in the info file takes precedence over an
1162 ;; existing entry in the dir file
1163 (setcdr dir-entry (cdr file-dir-entry)))
1164 (unless (or not-first-section
1165 (assoc (downcase
1094 (file-name-sans-extension 1166 (file-name-sans-extension
1095 (file-name-nondirectory file))) 1167 (file-name-nondirectory file)))
1096 dir-contents) 1168 dir-full-contents))
1097 file-dir-entry (Info-extract-dir-entries-from file)) 1169 (if file-dir-entry
1098 (if dir-entry 1170 (setq dir-section-contents (cons file-dir-entry
1099 (if file-dir-entry 1171 dir-section-contents))
1100 ;; A dir entry in the info file takes precedence over an 1172 (setq dir-section-contents
1101 ;; existing entry in the dir file 1173 (cons (list 'dummy
1102 (setcdr dir-entry (Info-parse-dir-entry file-dir-entry))) 1174 (capitalize (file-name-sans-extension
1103 (if file-dir-entry 1175 (file-name-nondirectory file)))
1104 (setq dir-contents (cons (cons 'dummy (Info-parse-dir-entry file-dir-entry)) 1176 ":"
1105 dir-contents)) 1177 (list Info-no-description-string))
1106 (setq dir-contents (cons (list 'dummy 1178 dir-section-contents))))))
1107 (capitalize (file-name-sans-extension 1179 Info-dir-newer-info-files)
1108 (file-name-nondirectory file))) 1180 (delete-region (point-min) (point-max))
1109 ":" 1181 (Info-dump-dir-entries (nreverse dir-section-contents))
1110 "[No description available]") 1182 (widen)
1111 dir-contents))))) 1183 (if (= next-section (point-max))
1112 Info-dir-newer-info-files) 1184 (setq next-section nil)
1113 (delete-region (point-min) (point-max)) 1185 (or (setq mark (and (re-search-forward "^\\* " nil t)
1114 (mapcar '(lambda (entry) 1186 (match-beginning 0)))
1115 (setq entry (cdr entry)) 1187 (throw 'done nil))
1116 (insert (format "* %s:" 1188 (setq next-section (or (and (re-search-forward "^[^* \t].*:[ \t]*$" nil t)
1117 (car entry))) 1189 (match-beginning 0))
1118 (setq entry (cdr entry)) 1190 (point-max))))
1119 (insert (car entry)) 1191 (setq not-first-section t)))
1120 (insert "\t" (car (cdr entry)) "\n")) 1192 (if to-temp
1121 (nreverse dir-contents)) 1193 (set-buffer-modified-p nil)
1122 (widen) 1194 (save-buffer))
1123 (if to-temp 1195 (if to-temp
1124 (set-buffer-modified-p nil) 1196 (message "Rebuilding temporary dir...done")
1125 (save-buffer)) 1197 (message "Rebuilding %s...done" file))))))
1126 (if to-temp
1127 (message "Rebuilding temporary dir...done")
1128 (message "Rebuilding %s...done" file)))))
1129 1198
1130 1199
1131 (defun Info-history-add (file node point) 1200 (defun Info-history-add (file node point)
1132 (if Info-keeping-history 1201 (if Info-keeping-history
1133 (let* ((name (format "(%s)%s" (Info-file-name-only file) node)) 1202 (let* ((name (format "(%s)%s" (Info-file-name-only file) node))