comparison lisp/info.el @ 371:cc15677e0335 r21-2b1

Import from CVS: tag r21-2b1
author cvs
date Mon, 13 Aug 2007 11:03:08 +0200
parents a4f53d9b3154
children 6240c7796c7a
comparison
equal deleted inserted replaced
370:bd866891f083 371:cc15677e0335
20 ;; WITHOUT ANY WARRANTY; without even the implied warranty of 20 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 ;; General Public License for more details. 22 ;; 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 XEmacs; see the file COPYING. If not, write to the 25 ;; along with XEmacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 ;; Boston, MA 02111-1307, USA. 27 ;; Boston, MA 02111-1307, USA.
28 28
29 ;;; Synched up with: Not synched with FSF. 29 ;;; Synched up with: Not synched with FSF.
30 30
394 use any existing `dir' or `localdir' file and ignore info 394 use any existing `dir' or `localdir' file and ignore info
395 directories containing none 395 directories containing none
396 `always' auto-generate a directory listing ignoring existing 396 `always' auto-generate a directory listing ignoring existing
397 `dir' and `localdir' files 397 `dir' and `localdir' files
398 `if-missing', the default, auto-generates a directory listing 398 `if-missing', the default, auto-generates a directory listing
399 if no `dir' or `localdir' file is present. Otherwise the 399 if no `dir' or `localdir' file is present. Otherwise the
400 contents of any of these files is used instead. 400 contents of any of these files is used instead.
401 `if-outdated' auto-generates a directory listing if the `dir' 401 `if-outdated' auto-generates a directory listing if the `dir'
402 and `localdir' are either inexistent or outdated (touched 402 and `localdir' are either inexistent or outdated (touched
403 less recently than an info file in the same directory)." 403 less recently than an info file in the same directory)."
404 :type '(choice (const :tag "never" never) 404 :type '(choice (const :tag "never" never)
405 (const :tag "always" always) 405 (const :tag "always" always)
406 (const :tag "if-missing" if-missing) 406 (const :tag "if-missing" if-missing)
407 (const :tag "if-outdated" if-outdated)) 407 (const :tag "if-outdated" if-outdated))
408 :group 'info) 408 :group 'info)
409 409
410 (defcustom Info-save-auto-generated-dir nil 410 (defcustom Info-save-auto-generated-dir nil
411 "*Whether an auto-generated info directory listing should be saved. 411 "*Whether an auto-generated info directory listing should be saved.
412 Possible values are: 412 Possible values are:
413 nil or `never', the default, auto-generated info directory 413 nil or `never', the default, auto-generated info directory
414 information will never be saved. 414 information will never be saved.
415 `always', auto-generated info directory information will be saved to 415 `always', auto-generated info directory information will be saved to
416 a `dir' file in the same directory overwriting it if it exists 416 a `dir' file in the same directory overwriting it if it exists
417 `conservative', auto-generated info directory information will be saved 417 `conservative', auto-generated info directory information will be saved
418 to a `dir' file in the same directory but the user is asked before 418 to a `dir' file in the same directory but the user is asked before
419 overwriting any existing file." 419 overwriting any existing file."
420 :type '(choice (const :tag "never" never) 420 :type '(choice (const :tag "never" never)
421 (const :tag "always" always) 421 (const :tag "always" always)
422 (const :tag "conservative" conservative)) 422 (const :tag "conservative" conservative))
423 :group 'info) 423 :group 'info)
424 424
425 (defconst Info-emacs-info-file-name "xemacs.info" 425 (defvar Info-emacs-info-file-name "xemacs.info"
426 "The filename of the XEmacs info for `Info-goto-emacs-command-node' 426 "The filename of the XEmacs info for
427 (`\\<help-mode-map>\\[Info-goto-emacs-command-node]')") 427 `Info-goto-emacs-command-node' (`\\<help-mode-map>\\[Info-goto-emacs-command-node]')")
428 428
429 ;;;###autoload 429 ;;;###autoload
430 (defvar Info-directory-list nil 430 (defvar Info-directory-list nil
431 "List of directories to search for Info documentation files. 431 "List of directories to search for Info documentation files.
432 432
433 The first directory in this list, the \"dir\" file there will become 433 The first directory in this list, the \"dir\" file there will become
434 the (dir)Top node of the Info documentation tree. 434 the (dir)Top node of the Info documentation tree. If you wish to
435 435 modify the info search path, use `M-x customize-variable,
436 Note: DO NOT use the `customize' interface to change the value of this 436 Info-directory-list' to do so.")
437 variable. Its value is created dynamically on each startup, depending 437
438 on XEmacs packages installed on the system. If you want to change the 438 (defcustom Info-localdir-heading-regexp
439 search path, make the needed modifications on the variable's value 439 "^Locally installed XEmacs Packages:?"
440 from .emacs. For instance:
441
442 (setq Info-directory-list (cons \"~/info\" Info-directory-list))")
443
444 ;; This could as well be hard-coded since ${srcdir}/info/dir is in CVS --dv
445 (defconst Info-localdir-heading-regexp "^Local Packages:$"
446 "The menu part of localdir files will be inserted below this topic 440 "The menu part of localdir files will be inserted below this topic
447 heading.") 441 heading."
442 :type 'regexp
443 :group 'info)
448 444
449 (defface info-node '((t (:bold t :italic t))) 445 (defface info-node '((t (:bold t :italic t)))
450 "Face used for node links in info." 446 "Face used for node links in info."
451 :group 'info-faces) 447 :group 'info-faces)
452 448
453 (defface info-xref '((t (:bold t))) 449 (defface info-xref '((t (:bold t)))
454 "Face used for cross-references in info." 450 "Face used for cross-references in info."
455 :group 'info-faces) 451 :group 'info-faces)
456 452
457 ;; This list is based on Karl Berry-s advice about extensions `info' itself 453 ;; Is this right for NT? .zip, with -c for to stdout, right?
458 ;; might encounter. --dv 454 (defvar Info-suffix-list '( ("" . nil)
459 (defcustom Info-suffix-list '(("" . nil) 455 (".info" . nil)
460 (".info" . nil) 456 (".info.gz" . "gzip -dc %s")
461 (".gz" . "gzip -dc %s") 457 (".info-z" . "gzip -dc %s")
462 (".info.gz" . "gzip -dc %s") 458 (".info.Z" . "uncompress -c %s")
463 (".z" . "gzip -dc %s") 459 (".gz" . "gzip -dc %s")
464 (".info.z" . "gzip -dc %s") 460 (".Z" . "uncompress -c %s")
465 (".bz2" . "bzip2 -dc %s") 461 (".zip" . "unzip -c %s") )
466 (".info.bz2" . "bzip2 -dc %s") 462 "List of file name suffixes and associated decoding commands.
467 (".Z" . "uncompress -c %s")
468 (".info.Z" . "uncompress -c %s")
469 (".zip" . "unzip -c %s")
470 (".info.zip" . "unzip -c %s")
471 (".y" . "cat %s | unyabba")
472 ("info.y" . "cat %s | unyabba")
473 ;; These ones are for MS-DOS filenames.
474 (".inf" . nil)
475 (".igz" . "gzip -dc %s")
476 (".inz" . "gzip -c %s"))
477 "*List of file name suffixes and associated decoding commands.
478 Each entry should be (SUFFIX . STRING); if STRING contains %s, that is 463 Each entry should be (SUFFIX . STRING); if STRING contains %s, that is
479 changed to name of the file to decode, otherwise the file is given to 464 changed to name of the file to decode, otherwise the file is given to
480 the command as standard input. If STRING is nil, no decoding is done." 465 the command as standard input. If STRING is nil, no decoding is done.")
481 :type '(repeat (cons (string :tag "suffix") 466
482 (choice :tag "command" 467 (defvar Info-footnote-tag "Note"
483 (const :tag "none" :value nil)
484 (string :tag ""))))
485 :group 'info)
486
487 (defcustom Info-footnote-tag "Note"
488 "*Symbol that identifies a footnote or cross-reference. 468 "*Symbol that identifies a footnote or cross-reference.
489 All \"*Note\" references will be changed to use this word instead." 469 All \"*Note\" references will be changed to use this word instead.")
490 :type 'string
491 :group 'info)
492 470
493 (defvar Info-current-file nil 471 (defvar Info-current-file nil
494 "Info file that Info is now looking at, or nil. 472 "Info file that Info is now looking at, or nil.
495 This is the name that was specified in Info, not the actual file name. 473 This is the name that was specified in Info, not the actual file name.
496 It doesn't contain directory names or file name extensions added by Info.") 474 It doesn't contain directory names or file name extensions added by Info.")
512 (defvar Info-current-annotation-completions nil 490 (defvar Info-current-annotation-completions nil
513 "Cached completion list for current annotation files.") 491 "Cached completion list for current annotation files.")
514 492
515 (defvar Info-index-alternatives nil 493 (defvar Info-index-alternatives nil
516 "List of possible matches for last Info-index command.") 494 "List of possible matches for last Info-index command.")
517
518 (defvar Info-index-first-alternative nil) 495 (defvar Info-index-first-alternative nil)
519 496
520 (defcustom Info-annotations-path '("~/.xemacs/info.notes" 497 (defcustom Info-annotations-path '("~/.xemacs/info.notes"
521 "~/.infonotes" 498 "~/.infonotes"
522 "/usr/lib/info.notes") 499 "/usr/lib/info.notes")
541 This is the file .../info/dir, which contains the topmost node of the 518 This is the file .../info/dir, which contains the topmost node of the
542 Info hierarchy. The first time you invoke Info you start off 519 Info hierarchy. The first time you invoke Info you start off
543 looking at that node, which is (dir)Top. 520 looking at that node, which is (dir)Top.
544  521 
545 File: dir Node: Top This is the top of the INFO tree 522 File: dir Node: Top This is the top of the INFO tree
546 This (the Directory node) gives a menu of major topics. 523 This (the Directory node) gives a menu of major topics.
547 524
548 * Menu: The list of major topics begins on the next line. 525 * Menu: The list of major topics begins on the next line.
549 526
550 ") 527 ")
551 528
552 (defcustom Info-no-description-string "[No description available]" 529 (defvar Info-no-description-string "[No description available]"
553 "*Description string for info files that have none" 530 "Description string for info files that have none")
554 :type 'string
555 :group 'info)
556 531
557 ;;;###autoload 532 ;;;###autoload
558 (defun info (&optional file) 533 (defun info (&optional file)
559 "Enter Info, the documentation browser. 534 "Enter Info, the documentation browser.
560 Optional argument FILE specifies the file to examine; 535 Optional argument FILE specifies the file to examine;
613 ;; empty filename is simple case 588 ;; empty filename is simple case
614 ((null filename) 589 ((null filename)
615 (Info-find-file-node nil nodename no-going-back tryfile line)) 590 (Info-find-file-node nil nodename no-going-back tryfile line))
616 ;; Convert filename to lower case if not found as specified. 591 ;; Convert filename to lower case if not found as specified.
617 ;; Expand it, look harder... 592 ;; Expand it, look harder...
618 ((let ((fname (substitute-in-file-name filename)) 593 ((let (temp temp-downcase found
619 temp found) 594 (fname (substitute-in-file-name filename)))
620 (let ((dirs (cond 595 (let ((dirs (cond
621 ;; If specified name starts with `./', then just try 596 ((string-match "^\\./" fname) ; If specified name starts with `./'
622 ;; current directory. No point in searching for an absolute 597 (list default-directory)) ; then just try current directory.
623 ;; file name
624 ((string-match "^\\./" fname)
625 (list default-directory))
626 ((file-name-absolute-p fname) 598 ((file-name-absolute-p fname)
627 '(nil)) 599 '(nil)) ; No point in searching for an absolute file name
628 (Info-additional-search-directory-list 600 (Info-additional-search-directory-list
629 (append Info-directory-list 601 (append Info-directory-list
630 Info-additional-search-directory-list)) 602 Info-additional-search-directory-list))
631 (t Info-directory-list)))) 603 (t Info-directory-list))))
632 ;; Search the directory list for file FNAME. 604 ;; Search the directory list for file FNAME.
633 (while (and dirs (not found)) 605 (while (and dirs (not found))
634 (setq temp (expand-file-name fname (car dirs))) 606 (setq temp (expand-file-name fname (car dirs)))
635 (setq found (Info-suffixed-file temp)) 607 (setq temp-downcase
608 (expand-file-name (downcase fname) (car dirs)))
609 (if (equal temp-downcase temp) (setq temp-downcase nil))
610 ;; Try several variants of specified name.
611 ;; Try downcasing, appending a suffix, or both.
612 (setq found (Info-suffixed-file temp temp-downcase))
636 (setq dirs (cdr dirs))) 613 (setq dirs (cdr dirs)))
637 (if found 614 (if found
638 (progn (setq filename (expand-file-name found)) 615 (progn (setq filename (expand-file-name found))
639 t)))) 616 t))))
640 (Info-find-file-node filename nodename no-going-back tryfile line)) 617 (Info-find-file-node filename nodename no-going-back tryfile line))
641 ;; Look for a URL. This pattern is stolen from w3.el to prevent 618 ;; Look for a URL. This pattern is stolen from w3.el to prevent
642 ;; loading it if we won't need it. 619 ;; loading it if we won't need it.
813 ;; constructed Info-dir-contents. 790 ;; constructed Info-dir-contents.
814 (defvar Info-dir-file-attributes nil) 791 (defvar Info-dir-file-attributes nil)
815 792
816 (defun Info-insert-dir () 793 (defun Info-insert-dir ()
817 "Construct the Info directory node by merging the files named 794 "Construct the Info directory node by merging the files named
818 \"dir\" or \"localdir\" from the directories in `Info-directory-list'. 795 \"dir\" or \"localdir\" from the directories in `Info-directory-list'
819 The \"dir\" files will take precedence in cases where both exist. It 796 The \"dir\" files will take precedence in cases where both exist. It
820 sets the *info* buffer's `default-directory' to the first directory we 797 sets the *info* buffer's `default-directory' to the first directory we
821 actually get any text from." 798 actually get any text from."
822 (if (and Info-dir-contents Info-dir-file-attributes 799 (if (and Info-dir-contents Info-dir-file-attributes
823 ;; Verify that none of the files we used has changed 800 ;; Verify that none of the files we used has changed
839 ;; Search the directory list for the directory file. 816 ;; Search the directory list for the directory file.
840 (while dirs 817 (while dirs
841 (let ((truename (file-truename (expand-file-name (car dirs))))) 818 (let ((truename (file-truename (expand-file-name (car dirs)))))
842 (or (member truename dirs-done) 819 (or (member truename dirs-done)
843 (member (directory-file-name truename) dirs-done) 820 (member (directory-file-name truename) dirs-done)
844 ;; Karl Berry recently added the ability all possibilities for 821 ;; Try several variants of specified name.
845 ;; extension as for normal info files. This code however is 822 ;; Try upcasing, appending `.info', or both.
846 ;; still unsatisfactory: if one day, we find a compressed dir 823 (let* (buf
847 ;; file (which looks possible), we should be able to handle it 824 file
848 ;; (which means decompress and read it, update it, save and 825 (attrs
849 ;; recompress it). --dv 826 (or
850 (let ((trials '("dir" "DIR" 827 (progn (setq file (expand-file-name "dir" truename))
851 "dir.info" "DIR.INFO" 828 (file-attributes file))
852 "dir.inf" "DIR.INF" 829 (progn (setq file (expand-file-name "DIR" truename))
853 "localdir" "LOCALDIR" 830 (file-attributes file))
854 "localdir.info" "LOCALDIR.INFO" 831 (progn (setq file (expand-file-name "dir.info" truename))
855 "localdir.inf" "LOCALDIR.INF")) 832 (file-attributes file))
856 buf file attrs) 833 (progn (setq file (expand-file-name "DIR.INFO" truename))
857 (catch 'found 834 (file-attributes file))
858 (while (setq file (pop trials)) 835 (progn (setq file (expand-file-name "localdir" truename))
859 (setq file (expand-file-name file truename)) 836 (file-attributes file))
860 (and (setq attrs (file-attributes file)) 837 (progn (setq file (expand-file-name "dir" truename))
861 (throw 'found t)))) 838 nil)
862 (unless file 839 )))
863 (setq file (expand-file-name "dir" truename)))
864 (setq dirs-done 840 (setq dirs-done
865 (cons truename 841 (cons truename
866 (cons (directory-file-name truename) 842 (cons (directory-file-name truename)
867 dirs-done))) 843 dirs-done)))
868 (Info-maybe-update-dir file) 844 (Info-maybe-update-dir file)
875 (set-buffer (or buf 851 (set-buffer (or buf
876 (generate-new-buffer 852 (generate-new-buffer
877 (if (string-match "localdir" file) 853 (if (string-match "localdir" file)
878 "localdir" 854 "localdir"
879 "info dir")))) 855 "info dir"))))
880 (if (not buf) 856 (if (not buf)
881 (insert-file-contents file)) 857 (insert-file-contents file))
882 (if (string-match "localdir" (buffer-name)) 858 (if (string-match "localdir" (buffer-name))
883 (setq lbuffers (cons (current-buffer) lbuffers)) 859 (setq lbuffers (cons (current-buffer) lbuffers))
884 (setq buffers (cons (current-buffer) buffers))) 860 (setq buffers (cons (current-buffer) buffers)))
885 (if attrs 861 (if attrs
886 (setq Info-dir-file-attributes 862 (setq Info-dir-file-attributes
887 (cons (cons file attrs) 863 (cons (cons file attrs)
888 Info-dir-file-attributes))))))) 864 Info-dir-file-attributes)))))))
889 (or (cdr dirs) (setq Info-dir-contents-directory (car dirs))) 865 (or (cdr dirs) (setq Info-dir-contents-directory (car dirs)))
890 (setq dirs (cdr dirs)))) 866 (setq dirs (cdr dirs))))
891 867
892 ;; ensure that the localdir files are inserted last, and reverse 868 ;; ensure that the localdir files are inserted last, and reverse
893 ;; the list of them so that when they get pushed in, they appear 869 ;; the list of them so that when they get pushed in, they appear
894 ;; in the same order they got specified in the path, from top to 870 ;; in the same order they got specified in the path, from top to
895 ;; bottom. 871 ;; bottom.
896 (nconc buffers (reverse lbuffers)) 872 (nconc buffers (reverse lbuffers))
897 873
898 (or buffers 874 (or buffers
899 (error "Can't find the Info directory node")) 875 (error "Can't find the Info directory node"))
900 ;; Distinguish the dir file that comes with Emacs from all the 876 ;; Distinguish the dir file that comes with Emacs from all the
901 ;; others. Yes, that is really what this is supposed to do. 877 ;; others. Yes, that is really what this is supposed to do.
902 ;; If it doesn't work, fix it. 878 ;; If it doesn't work, fix it.
961 (search-forward "\n\^_" nil 'move) 937 (search-forward "\n\^_" nil 'move)
962 (beginning-of-line) 938 (beginning-of-line)
963 (setq end (point)) 939 (setq end (point))
964 (setq nodes (cons (list nodename other beg end) nodes)))))) 940 (setq nodes (cons (list nodename other beg end) nodes))))))
965 (setq others (cdr others)))) 941 (setq others (cdr others))))
966 942
967 ;; Add to the main menu a menu item for each other node. 943 ;; Add to the main menu a menu item for each other node.
968 (re-search-forward "^\\* Menu:" nil t) 944 (re-search-forward "^\\* Menu:" nil t)
969 (forward-line 1) 945 (forward-line 1)
970 (let ((menu-items '("top")) 946 (let ((menu-items '("top"))
971 (nodes nodes) 947 (nodes nodes)
1014 (message "Composing main Info directory...done")) 990 (message "Composing main Info directory...done"))
1015 (setq Info-dir-contents (buffer-string))) 991 (setq Info-dir-contents (buffer-string)))
1016 (setq default-directory Info-dir-contents-directory) 992 (setq default-directory Info-dir-contents-directory)
1017 (setq buffer-file-name (caar Info-dir-file-attributes))) 993 (setq buffer-file-name (caar Info-dir-file-attributes)))
1018 994
1019 (defmacro Info-directory-files (dir-file &optional all full nosort files-only)
1020 "Return a list of Info files living in the same directory as DIR-FILE.
1021 This list actually contains the files living in this directory, except for
1022 the dir file itself and the secondary info files (foo-1 foo-2 etc).
1023
1024 If the optional argument ALL is non nil, the secondary info files are also
1025 included in the list.
1026
1027 Please refer to the function `directory-files' for the meaning of the other
1028 optional arguments."
1029 `(let* ((dir (file-name-directory ,dir-file))
1030 (all-files (remove ,dir-file (directory-files dir ',full nil ',nosort
1031 ',files-only))))
1032 (setq all-files
1033 (if ,full
1034 (remove (concat dir ".")
1035 (remove (concat dir "..") all-files))
1036 (remove "."
1037 (remove ".." all-files))))
1038 (if ,all
1039 all-files
1040 (let ((suff-match
1041 (concat "-[0-9]+\\("
1042 ;; Extract all known compression suffixes from
1043 ;; Info-suffix-list. These suffixes can typically be
1044 ;; found in entries of the form `.info.something'.
1045 (let ((suff-list Info-suffix-list)
1046 suff regexp)
1047 (while (setq suff (pop suff-list))
1048 (and (string-match "^\\.info" (car suff))
1049 (setq regexp (concat regexp
1050 (regexp-quote
1051 (substring
1052 (car suff) 5))
1053 (and suff-list "\\|")))))
1054 regexp)
1055 "\\)?$"))
1056 info-files file)
1057 (while (setq file (pop all-files))
1058 (or (string-match suff-match file)
1059 (push file info-files)))
1060 (reverse info-files)
1061 ))
1062 ))
1063
1064 (defun Info-maybe-update-dir (file) 995 (defun Info-maybe-update-dir (file)
1065 "Rebuild dir or localdir according to `Info-auto-generate-directory'." 996 "Rebuild dir or localdir according to `Info-auto-generate-directory'."
1066 (unless (or (not (file-exists-p (file-name-directory file))) 997 (unless (or (not (file-exists-p (file-name-directory file)))
1067 (null (Info-directory-files file 'all))) 998 (null (directory-files (file-name-directory file) nil "\\.info")))
1068 (if (not (find-buffer-visiting file)) 999 (if (not (find-buffer-visiting file))
1069 (if (not (file-exists-p file)) 1000 (if (not (file-exists-p file))
1070 (if (or (eq Info-auto-generate-directory 'always) 1001 (if (or (eq Info-auto-generate-directory 'always)
1071 (eq Info-auto-generate-directory 'if-missing)) 1002 (eq Info-auto-generate-directory 'if-missing))
1072 (Info-build-dir-anew (file-name-directory file))) 1003 (Info-build-dir-anew (file-name-directory file)))
1073 (if (or (eq Info-auto-generate-directory 'always) 1004 (if (or (eq Info-auto-generate-directory 'always)
1074 (and (eq Info-auto-generate-directory 'if-outdated) 1005 (and (eq Info-auto-generate-directory 'if-outdated)
1075 (Info-dir-outdated-p file))) 1006 (Info-dir-outdated-p file)))
1076 (Info-rebuild-dir file)))))) 1007 (Info-rebuild-dir file))))))
1081 (defun Info-dir-outdated-p (file) 1012 (defun Info-dir-outdated-p (file)
1082 "Return non-nil if dir or localdir is outdated. 1013 "Return non-nil if dir or localdir is outdated.
1083 dir or localdir are outdated when an info file in the same 1014 dir or localdir are outdated when an info file in the same
1084 directory has been modified more recently." 1015 directory has been modified more recently."
1085 (let ((dir-mod-time (nth 5 (file-attributes file))) 1016 (let ((dir-mod-time (nth 5 (file-attributes file)))
1086 f-mod-time newer) 1017 f-mod-time
1018 newer)
1087 (setq Info-dir-newer-info-files nil) 1019 (setq Info-dir-newer-info-files nil)
1088 (mapcar 1020 (mapcar
1089 '(lambda (f) 1021 '(lambda (f)
1090 (prog2 1022 (prog2
1091 (setq f-mod-time (nth 5 (file-attributes f))) 1023 (setq f-mod-time (nth 5 (file-attributes f)))
1092 (setq newer (or (> (car f-mod-time) (car dir-mod-time)) 1024 (setq newer (or (> (car f-mod-time) (car dir-mod-time))
1093 (and (= (car f-mod-time) (car dir-mod-time)) 1025 (and (= (car f-mod-time) (car dir-mod-time))
1094 (> (car (cdr f-mod-time)) 1026 (> (car (cdr f-mod-time)) (car (cdr dir-mod-time))))))
1095 (car (cdr dir-mod-time)))))) 1027 (if (and (file-readable-p f)
1096 (if (and (file-readable-p f) newer) 1028 newer)
1097 (setq Info-dir-newer-info-files 1029 (setq Info-dir-newer-info-files
1098 (cons f Info-dir-newer-info-files))))) 1030 (cons f Info-dir-newer-info-files)))))
1099 (Info-directory-files file nil 'fullname 'nosort t)) 1031 (directory-files (file-name-directory file)
1032 'fullname
1033 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$"
1034 'nosort
1035 t))
1100 Info-dir-newer-info-files)) 1036 Info-dir-newer-info-files))
1101 1037
1102 (defun Info-extract-dir-entry-from (file) 1038 (defun Info-extract-dir-entry-from (file)
1103 "Extract the dir entry from the info FILE. 1039 "Extract the dir entry from the info FILE.
1104 The dir entry is delimited by the markers `START-INFO-DIR-ENTRY' 1040 The dir entry is delimited by the markers `START-INFO-DIR-ENTRY'
1122 (let (entry entries) 1058 (let (entry entries)
1123 (save-excursion 1059 (save-excursion
1124 (save-restriction 1060 (save-restriction
1125 (narrow-to-region beg end) 1061 (narrow-to-region beg end)
1126 (goto-char beg) 1062 (goto-char beg)
1127 (while (re-search-forward 1063 (while (re-search-forward "^\\* \\([^:]+\\):\\([ \t]*(\\([^)]*\\))\\w*\\.\\|:\\)" nil t)
1128 "^\\* \\([^:]+\\):\\([ \t]*(\\([^)]*\\))\\w*\\.\\|:\\)" nil t)
1129 (setq entry (list (match-string 2) 1064 (setq entry (list (match-string 2)
1130 (match-string 1) 1065 (match-string 1)
1131 (downcase (or (match-string 3) 1066 (downcase (or (match-string 3)
1132 (match-string 1))))) 1067 (match-string 1)))))
1133 (setq entry 1068 (setq entry
1134 (cons (nreverse 1069 (cons (nreverse
1135 (cdr 1070 (cdr
1136 (nreverse 1071 (nreverse
1137 (split-string 1072 (split-string
1138 (buffer-substring 1073 (buffer-substring
1139 (re-search-forward "[ \t]*" nil t) 1074 (re-search-forward "[ \t]*" nil t)
1140 (or (and (re-search-forward "^[^ \t]" nil t) 1075 (or (and (re-search-forward "^[^ \t]" nil t)
1141 (goto-char (match-beginning 0))) 1076 (goto-char (match-beginning 0)))
1142 (point-max))) 1077 (point-max)))
1143 "[ \t]*\n[ \t]*")))) 1078 "[ \t]*\n[ \t]*"))))
1154 (setq len (length (concat (car e) 1089 (setq len (length (concat (car e)
1155 (car (cdr e))))) 1090 (car (cdr e)))))
1156 (if (> len description-col) 1091 (if (> len description-col)
1157 (setq description-col len))) 1092 (setq description-col len)))
1158 entries) 1093 entries)
1159 (setq description-col (+ 5 description-col)) 1094 (setq description-col (+ 5 description-col))
1160 (mapcar '(lambda (e) 1095 (mapcar '(lambda (e)
1161 (setq e (cdr e)) ; Drop filename 1096 (setq e (cdr e)) ; Drop filename
1162 (insert "* " (car e) ":" (car (cdr e))) 1097 (insert "* " (car e) ":" (car (cdr e)))
1163 (setq e (car (cdr (cdr e)))) 1098 (setq e (car (cdr (cdr e))))
1164 (while e 1099 (while e
1169 (insert "\n"))) 1104 (insert "\n")))
1170 1105
1171 1106
1172 (defun Info-build-dir-anew (directory) 1107 (defun Info-build-dir-anew (directory)
1173 "Build info directory information for DIRECTORY. 1108 "Build info directory information for DIRECTORY.
1174 The generated directory listing may be saved to a `dir' according 1109 The generated directory listing may be saved to a `dir' according
1175 to the value of `Info-save-auto-generated-dir'" 1110 to the value of `Info-save-auto-generated-dir'"
1176 (save-excursion 1111 (save-excursion
1177 (let* ((dirfile (expand-file-name "dir" directory)) 1112 (let* ((dirfile (expand-file-name "dir" directory))
1178 (to-temp (or (null Info-save-auto-generated-dir) 1113 (to-temp (or (null Info-save-auto-generated-dir)
1179 (eq Info-save-auto-generated-dir 'never) 1114 (eq Info-save-auto-generated-dir 'never)
1180 (and (not (file-writable-p dirfile)) 1115 (and (not (file-writable-p dirfile))
1181 (message "File not writable %s. Using temporary." 1116 (message "File not writable %s. Using temporary." dirfile))))
1182 dirfile)))) 1117 (info-files
1183 (info-files (Info-directory-files dirfile nil 'fullname nil t))) 1118 (directory-files directory
1119 'fullname
1120 ".*\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$"
1121 nil
1122 t)))
1184 (if to-temp 1123 (if to-temp
1185 (message "Creating temporary dir in %s..." directory) 1124 (message "Creating temporary dir in %s..." directory)
1186 (message "Creating %s..." dirfile)) 1125 (message "Creating %s..." dirfile))
1187 (set-buffer (find-file-noselect dirfile t)) 1126 (set-buffer (find-file-noselect dirfile t))
1188 (setq buffer-read-only nil) 1127 (setq buffer-read-only nil)
1189 (erase-buffer) 1128 (erase-buffer)
1190 (insert Info-dir-prologue "Info files in " directory ":\n\n") 1129 (insert Info-dir-prologue
1191 (Info-dump-dir-entries 1130 "Info files in " directory ":\n\n")
1192 (mapcar 1131 (Info-dump-dir-entries
1132 (mapcar
1193 '(lambda (f) 1133 '(lambda (f)
1194 (or (Info-extract-dir-entry-from f) 1134 (or (Info-extract-dir-entry-from f)
1195 (list 'dummy 1135 (list 'dummy
1196 (progn (string-match "\\([^.]*\\)\\(\\..*\\)?$" 1136 (progn
1197 (file-name-nondirectory f)) 1137 (string-match "\\(.*\\)\\.info\\(.gz\\|.Z\\|-z\\|.zip\\)?$"
1198 (capitalize 1138 (file-name-nondirectory f))
1199 (match-string 1 (file-name-nondirectory f)))) 1139 (capitalize (match-string 1 (file-name-nondirectory f))))
1200 ":" 1140 ":"
1201 (list Info-no-description-string)))) 1141 (list Info-no-description-string))))
1202 info-files)) 1142 info-files))
1203 (if to-temp 1143 (if to-temp
1204 (set-buffer-modified-p nil) 1144 (set-buffer-modified-p nil)
1208 (message "Creating %s...done" dirfile))))) 1148 (message "Creating %s...done" dirfile)))))
1209 1149
1210 1150
1211 (defun Info-rebuild-dir (file) 1151 (defun Info-rebuild-dir (file)
1212 "Build info directory information in the directory of dir FILE. 1152 "Build info directory information in the directory of dir FILE.
1213 Description of info files are merged from the info files in the 1153 Description of info files are merged from the info files in the
1214 directory and the contents of FILE with the description in info files 1154 directory and the contents of FILE with the description in info files
1215 taking precedence over descriptions in FILE. 1155 taking precedence over descriptions in FILE.
1216 The generated directory listing may be saved to a `dir' according to 1156 The generated directory listing may be saved to a `dir' according to
1217 the value of `Info-save-auto-generated-dir' " 1157 the value of `Info-save-auto-generated-dir' "
1218 (save-excursion 1158 (save-excursion
1219 (save-restriction 1159 (save-restriction
1220 (let (dir-section-contents dir-full-contents 1160 (let (dir-section-contents dir-full-contents
1221 dir-entry 1161 dir-entry
1222 file-dir-entry 1162 file-dir-entry
1223 mark next-section 1163 mark next-section
1224 not-first-section 1164 not-first-section
1225 (to-temp 1165 (to-temp
1226 (or (null Info-save-auto-generated-dir) 1166 (or (null Info-save-auto-generated-dir)
1227 (eq Info-save-auto-generated-dir 'never) 1167 (eq Info-save-auto-generated-dir 'never)
1228 (and (eq Info-save-auto-generated-dir 'always) 1168 (and (eq Info-save-auto-generated-dir 'always)
1229 (not (file-writable-p file)) 1169 (not (file-writable-p file))
1230 (message "File not writable %s. Using temporary." file)) 1170 (message "File not writable %s. Using temporary." file))
1231 (and (eq Info-save-auto-generated-dir 'conservative) 1171 (and (eq Info-save-auto-generated-dir 'conservative)
1232 (or (and (not (file-writable-p file)) 1172 (or (and (not (file-writable-p file))
1233 (message 1173 (message "File not writable %s. Using temporary." file))
1234 "File not writable %s. Using temporary." file)) 1174 (not (y-or-n-p
1235 (not (y-or-n-p 1175 (message "%s is outdated. Overwrite ? "
1236 (message "%s is outdated. Overwrite ? "
1237 file)))))))) 1176 file))))))))
1238 (set-buffer (find-file-noselect file t)) 1177 (set-buffer (find-file-noselect file t))
1239 (setq buffer-read-only nil) 1178 (setq buffer-read-only nil)
1240 (if to-temp 1179 (if to-temp
1241 (message "Rebuilding temporary %s..." file) 1180 (message "Rebuilding temporary %s..." file)
1247 (re-search-forward "^\\* Menu:.*$" nil t) 1186 (re-search-forward "^\\* Menu:.*$" nil t)
1248 (setq mark (and (re-search-forward "^\\* " nil t) 1187 (setq mark (and (re-search-forward "^\\* " nil t)
1249 (match-beginning 0)))) 1188 (match-beginning 0))))
1250 (throw 'done nil)) 1189 (throw 'done nil))
1251 (setq dir-full-contents (Info-parse-dir-entries mark (point-max))) 1190 (setq dir-full-contents (Info-parse-dir-entries mark (point-max)))
1252 (setq next-section (or (and (re-search-forward 1191 (setq next-section (or (and (re-search-forward "^[^* \t].*:[ \t]*$" nil t)
1253 "^[^* \t].*:[ \t]*$" nil t)
1254 (match-beginning 0)) 1192 (match-beginning 0))
1255 (point-max))) 1193 (point-max)))
1256 (while next-section 1194 (while next-section
1257 (narrow-to-region mark next-section) 1195 (narrow-to-region mark next-section)
1258 (setq dir-section-contents (nreverse (Info-parse-dir-entries 1196 (setq dir-section-contents (nreverse (Info-parse-dir-entries (point-min)
1259 (point-min) (point-max)))) 1197 (point-max))))
1260 (mapcar 1198 (mapcar '(lambda (file)
1261 '(lambda (file) 1199 (setq dir-entry (assoc (downcase
1262 (setq dir-entry (assoc (downcase 1200 (file-name-sans-extension
1263 (file-name-sans-extension 1201 (file-name-nondirectory file)))
1264 (file-name-nondirectory file))) 1202 dir-section-contents)
1265 dir-section-contents) 1203 file-dir-entry (Info-extract-dir-entry-from file))
1266 file-dir-entry (Info-extract-dir-entry-from file)) 1204 (if dir-entry
1267 (if dir-entry 1205 (if file-dir-entry
1268 (if file-dir-entry 1206 ;; A dir entry in the info file takes precedence over an
1269 ;; A dir entry in the info file takes precedence over 1207 ;; existing entry in the dir file
1270 ;; an existing entry in the dir file 1208 (setcdr dir-entry (cdr file-dir-entry)))
1271 (setcdr dir-entry (cdr file-dir-entry))) 1209 (unless (or not-first-section
1272 (unless (or not-first-section 1210 (assoc (downcase
1273 (assoc (downcase 1211 (file-name-sans-extension
1274 (file-name-sans-extension 1212 (file-name-nondirectory file)))
1275 (file-name-nondirectory file))) 1213 dir-full-contents))
1276 dir-full-contents)) 1214 (if file-dir-entry
1277 (if file-dir-entry 1215 (setq dir-section-contents (cons file-dir-entry
1278 (setq dir-section-contents 1216 dir-section-contents))
1279 (cons file-dir-entry dir-section-contents)) 1217 (setq dir-section-contents
1280 (setq dir-section-contents 1218 (cons (list 'dummy
1281 (cons (list 'dummy 1219 (capitalize (file-name-sans-extension
1282 (capitalize (file-name-sans-extension 1220 (file-name-nondirectory file)))
1283 (file-name-nondirectory 1221 ":"
1284 file))) 1222 (list Info-no-description-string))
1285 ":" 1223 dir-section-contents))))))
1286 (list Info-no-description-string)) 1224 Info-dir-newer-info-files)
1287 dir-section-contents))))))
1288 Info-dir-newer-info-files)
1289 (delete-region (point-min) (point-max)) 1225 (delete-region (point-min) (point-max))
1290 (Info-dump-dir-entries (nreverse dir-section-contents)) 1226 (Info-dump-dir-entries (nreverse dir-section-contents))
1291 (widen) 1227 (widen)
1292 (if (= next-section (point-max)) 1228 (if (= next-section (point-max))
1293 (setq next-section nil) 1229 (setq next-section nil)
1294 (or (setq mark (and (re-search-forward "^\\* " nil t) 1230 (or (setq mark (and (re-search-forward "^\\* " nil t)
1295 (match-beginning 0))) 1231 (match-beginning 0)))
1296 (throw 'done nil)) 1232 (throw 'done nil))
1297 (setq next-section (or (and (re-search-forward 1233 (setq next-section (or (and (re-search-forward "^[^* \t].*:[ \t]*$" nil t)
1298 "^[^* \t].*:[ \t]*$" nil t)
1299 (match-beginning 0)) 1234 (match-beginning 0))
1300 (point-max)))) 1235 (point-max))))
1301 (setq not-first-section t))) 1236 (setq not-first-section t)))
1302 (if to-temp 1237 (if to-temp
1303 (progn 1238 (progn
1304 (set-buffer-modified-p nil) 1239 (set-buffer-modified-p nil)
1305 (message "Rebuilding temporary %s...done" file)) 1240 (message "Rebuilding temporary %s...done" file))
1306 (save-buffer) 1241 (save-buffer)
1307 (message "Rebuilding %s...done" file)))))) 1242 (message "Rebuilding %s...done" file))))))
1308 1243
1309 ;;;###autoload 1244 ;;;###autoload
1310 (defun Info-batch-rebuild-dir () 1245 (defun Info-batch-rebuild-dir ()
1311 "(Re)build `dir' files in the directories remaining on the command line. 1246 "(Re)build info `dir' files in the directories remaining on the command line.
1312 Use this from the command line, with `-batch', it won't work in an 1247 Use this from the command line, with `-batch';
1313 interactive XEmacs. 1248 it won't work in an interactive Emacs.
1314 1249 Each file is processed even if an error occurred previously.
1315 Each file is processed even if an error occurred previously. For example, 1250 For example, invoke \"xemacs -batch -f Info-batch-rebuild-dir /usr/local/info\""
1316 invoke \"xemacs -batch -f Info-batch-rebuild-dir /usr/local/info\""
1317 ;; command-line-args-left is what is left of the command line (from 1251 ;; command-line-args-left is what is left of the command line (from
1318 ;; startup.el) 1252 ;; startup.el)
1319 (defvar command-line-args-left) ; Avoid 'free variable' warning 1253 (defvar command-line-args-left) ; Avoid 'free variable' warning
1320 (if (not noninteractive) 1254 (if (not noninteractive)
1321 (error "`Info-batch-rebuild-dir' is to be used only with -batch")) 1255 (error "`Info-batch-rebuild-dir' is to be used only with -batch"))
1324 (while command-line-args-left 1258 (while command-line-args-left
1325 (if (not (file-directory-p (car command-line-args-left))) 1259 (if (not (file-directory-p (car command-line-args-left)))
1326 (message "Warning: Skipped %s. Not a directory." 1260 (message "Warning: Skipped %s. Not a directory."
1327 (car command-line-args-left)) 1261 (car command-line-args-left))
1328 (setq dir (expand-file-name "dir" (car command-line-args-left))) 1262 (setq dir (expand-file-name "dir" (car command-line-args-left)))
1329 (setq localdir (expand-file-name "localdir" 1263 (setq localdir (expand-file-name "localdir" (car command-line-args-left)))
1330 (car command-line-args-left))) 1264 (cond
1331 (cond
1332 ((file-exists-p dir) 1265 ((file-exists-p dir)
1333 (Info-rebuild-dir dir)) 1266 (Info-rebuild-dir dir))
1334 ((file-exists-p localdir) 1267 ((file-exists-p localdir)
1335 (Info-rebuild-dir localdir)) 1268 (Info-rebuild-dir localdir))
1336 (t 1269 (t
1389 (widen) 1322 (widen)
1390 (erase-buffer) 1323 (erase-buffer)
1391 (Info-insert-file-contents (Info-suffixed-file 1324 (Info-insert-file-contents (Info-suffixed-file
1392 (expand-file-name lastfilename 1325 (expand-file-name lastfilename
1393 (file-name-directory 1326 (file-name-directory
1394 Info-current-file)) 1327 Info-current-file)))
1395 'exact)
1396 t) 1328 t)
1397 (set-buffer-modified-p nil) 1329 (set-buffer-modified-p nil)
1398 (setq Info-current-subfile lastfilename))) 1330 (setq Info-current-subfile lastfilename)))
1399 (goto-char (point-min)) 1331 (goto-char (point-min))
1400 (search-forward "\n\^_") 1332 (search-forward "\n\^_")
1401 (+ (- nodepos lastfilepos) (point)))) 1333 (+ (- nodepos lastfilepos) (point))))
1402 1334
1403 (defun Info-all-case-regexp (str) 1335 (defun Info-suffixed-file (name &optional name2)
1404 (let ((regexp "") 1336 "Look for NAME with each of the `Info-suffix-list' extensions in
1405 (len (length str)) 1337 turn. Optional NAME2 is the name of a fallback info file to check
1406 (i 0) 1338 for; usually a downcased version of NAME."
1407 c) 1339 (let ((suff Info-suffix-list)
1408 (while (< i len) 1340 (found nil)
1409 (setq c (aref str i)) 1341 file file2)
1410 (cond ((or (and (>= c ?A) (<= c ?Z)) 1342 (while (and suff (not found))
1411 (and (>= c ?a) (<= c ?z))) 1343 (setq file (concat name (caar suff))
1412 (setq regexp (concat regexp 1344 file2 (and name2 (concat name2 (caar suff))))
1413 "[" 1345 (cond
1414 (char-to-string (downcase c)) 1346 ((file-regular-p file)
1415 "\\|" 1347 (setq found file))
1416 (char-to-string (upcase c)) 1348 ((and file2 (file-regular-p file2))
1417 "]"))) 1349 (setq found file2))
1418 (t 1350 (t
1419 (setq regexp (concat regexp (char-to-string c))))) 1351 (setq suff (cdr suff)))))
1420 (setq i (1+ i))) 1352 (or found
1421 regexp)) 1353 (and name (when (file-regular-p name)
1422 1354 name))
1423 (defun Info-suffixed-file (name &optional exact) 1355 (and name2 (when (file-regular-p name2)
1424 "Look for an info file named NAME. This function tries to be smart in 1356 name2)))))
1425 finding the file corresponding to NAME: if it doesn't exist, several
1426 variants are looked for, notably by appending suffixes from
1427 `Info-suffix-list' and by trying to change the characters case in NAME.
1428
1429 The optional argument EXACT prevents this function from trying different case
1430 versions of NAME. Only the suffixes are tried."
1431 (catch 'found
1432 ;; First, try NAME alone:
1433 (and (file-regular-p name) (throw 'found name))
1434 ;; Then, try different variants
1435 (let ((suff-match (concat "\\("
1436 (let ((suff-list Info-suffix-list)
1437 suff regexp)
1438 (while (setq suff (pop suff-list))
1439 (setq regexp
1440 (concat regexp
1441 (regexp-quote (car suff))
1442 (and suff-list "\\|"))))
1443 regexp)
1444 "\\)?$"))
1445 (dir (file-name-directory name))
1446 file files)
1447 (setq name (file-name-nondirectory name))
1448 (setq files
1449 (condition-case data ;; protect against invalid directory
1450 ;; First, try NAME[.<suffix>]
1451 (append
1452 (directory-files dir 'fullname
1453 (concat "^" (regexp-quote name) suff-match)
1454 nil t)
1455 (if exact
1456 nil
1457 ;; Then, try to match the name independantly of the
1458 ;; characters case.
1459 (directory-files dir 'fullname
1460 (Info-all-case-regexp
1461 (concat "^"
1462 (regexp-quote name)
1463 suff-match))
1464 nil t)))
1465 (t
1466 (display-warning 'info
1467 (format "directory `%s' error: %s" dir data))
1468 nil)))
1469 (while (setq file (pop files))
1470 (and (file-regular-p file)
1471 (throw 'found file)))
1472 )))
1473 1357
1474 (defun Info-insert-file-contents (file &optional visit) 1358 (defun Info-insert-file-contents (file &optional visit)
1475 (setq file (expand-file-name file default-directory)) 1359 (setq file (expand-file-name file default-directory))
1476 (let ((suff Info-suffix-list) 1360 (let ((suff Info-suffix-list))
1477 len) 1361 (while (and suff (or (<= (length file) (length (car (car suff))))
1478 (while (and suff 1362 (not (equal (substring file
1479 (setq len (length (car (car suff)))) 1363 (- (length (car (car suff)))))
1480 (or (<= (length file) len) 1364 (car (car suff))))))
1481 (not (or
1482 (equal (substring file (- len))
1483 (car (car suff)))
1484 (equal (substring file (- len))
1485 (upcase (car (car suff)))))
1486 )))
1487 (setq suff (cdr suff))) 1365 (setq suff (cdr suff)))
1488 (if (stringp (cdr (car suff))) 1366 (if (stringp (cdr (car suff)))
1489 (let ((command (if (string-match "%s" (cdr (car suff))) 1367 (let ((command (if (string-match "%s" (cdr (car suff)))
1490 (format (cdr (car suff)) file) 1368 (format (cdr (car suff)) file)
1491 (concat (cdr (car suff)) " < " file)))) 1369 (concat (cdr (car suff)) " < " file))))
1551 (list (cons modeline-buffer-id-left-extent "Info: ") 1429 (list (cons modeline-buffer-id-left-extent "Info: ")
1552 (cons modeline-buffer-id-right-extent 1430 (cons modeline-buffer-id-right-extent
1553 (concat 1431 (concat
1554 "(" 1432 "("
1555 (if Info-current-file 1433 (if Info-current-file
1556 (let ((name (file-name-nondirectory 1434 (let ((name (file-name-nondirectory Info-current-file)))
1557 Info-current-file))) 1435 (if (string-match "\\.info$" name)
1558 (if (string-match "^\\([^.]*\\)\\..*$" name) 1436 (substring name 0 -5)
1559 (match-string 1 name)
1560 name)) 1437 name))
1561 "") 1438 "")
1562 ")" 1439 ")"
1563 (or Info-current-node "")))))) 1440 (or Info-current-node ""))))))
1564 1441
1658 (defun Info-build-node-completions () 1535 (defun Info-build-node-completions ()
1659 (or Info-current-file-completions 1536 (or Info-current-file-completions
1660 (let ((compl (Info-build-annotation-completions))) 1537 (let ((compl (Info-build-annotation-completions)))
1661 (save-excursion 1538 (save-excursion
1662 (save-restriction 1539 (save-restriction
1663 (widen)
1664 (if (marker-buffer Info-tag-table-marker) 1540 (if (marker-buffer Info-tag-table-marker)
1665 (progn 1541 (progn
1666 (set-buffer (marker-buffer Info-tag-table-marker)) 1542 (set-buffer (marker-buffer Info-tag-table-marker))
1667 (goto-char Info-tag-table-marker) 1543 (goto-char Info-tag-table-marker)
1668 (while (re-search-forward "\nNode: \\(.*\\)\177" nil t) 1544 (while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
1669 (setq compl 1545 (setq compl
1670 (cons (list (buffer-substring (match-beginning 1) 1546 (cons (list (buffer-substring (match-beginning 1)
1671 (match-end 1))) 1547 (match-end 1)))
1672 compl)))) 1548 compl))))
1549 (widen)
1673 (goto-char (point-min)) 1550 (goto-char (point-min))
1674 (while (search-forward "\n\^_" nil t) 1551 (while (search-forward "\n\^_" nil t)
1675 (forward-line 1) 1552 (forward-line 1)
1676 (let ((beg (point))) 1553 (let ((beg (point)))
1677 (forward-line 1) 1554 (forward-line 1)
1678 (if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]" 1555 (if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]"
1679 beg t) 1556 beg t)
1680 (setq compl 1557 (setq compl
1681 (cons (list (buffer-substring (match-beginning 1) 1558 (cons (list (buffer-substring (match-beginning 1)
1682 (match-end 1))) 1559 (match-end 1)))
1683 compl)))))))) 1560 compl))))))))
1684 (setq Info-current-file-completions compl)))) 1561 (setq Info-current-file-completions compl))))
1685 1562
1706 (if (null Info-current-subfile) 1583 (if (null Info-current-subfile)
1707 (progn (re-search-forward regexp) (setq found (point))) 1584 (progn (re-search-forward regexp) (setq found (point)))
1708 (condition-case nil 1585 (condition-case nil
1709 (progn (re-search-forward regexp) (setq found (point))) 1586 (progn (re-search-forward regexp) (setq found (point)))
1710 (search-failed nil))))) 1587 (search-failed nil)))))
1711 (if (not found) 1588 (if (not found) ;can only happen in subfile case -- else would have erred
1712 ;; can only happen in subfile case -- else would have erred
1713 (unwind-protect 1589 (unwind-protect
1714 (let ((list ())) 1590 (let ((list ()))
1715 (set-buffer (marker-buffer Info-tag-table-marker)) 1591 (set-buffer (marker-buffer Info-tag-table-marker))
1716 (goto-char (point-min)) 1592 (goto-char (point-min))
1717 (search-forward "\n\^_\nIndirect:") 1593 (search-forward "\n\^_\nIndirect:")
1724 (beginning-of-line) 1600 (beginning-of-line)
1725 (while (not (eobp)) 1601 (while (not (eobp))
1726 (re-search-forward "\\(^.*\\): [0-9]+$") 1602 (re-search-forward "\\(^.*\\): [0-9]+$")
1727 (goto-char (+ (match-end 1) 2)) 1603 (goto-char (+ (match-end 1) 2))
1728 (setq list (cons (cons (read (current-buffer)) 1604 (setq list (cons (cons (read (current-buffer))
1729 (buffer-substring 1605 (buffer-substring (match-beginning 1)
1730 (match-beginning 1) 1606 (match-end 1)))
1731 (match-end 1)))
1732 list)) 1607 list))
1733 (goto-char (1+ (match-end 0)))) 1608 (goto-char (1+ (match-end 0))))
1734 (setq list (nreverse list) 1609 (setq list (nreverse list)
1735 list (cdr list))) 1610 list (cdr list)))
1736 (while list 1611 (while list
1753 (or (and (equal onode Info-current-node) 1628 (or (and (equal onode Info-current-node)
1754 (equal ofile Info-current-file)) 1629 (equal ofile Info-current-file))
1755 (Info-history-add ofile onode opoint))))) 1630 (Info-history-add ofile onode opoint)))))
1756 1631
1757 ;; Extract the value of the node-pointer named NAME. 1632 ;; Extract the value of the node-pointer named NAME.
1758 ;; If there is none, use ERRORNAME in the error message; 1633 ;; If there is none, use ERRORNAME in the error message;
1759 ;; if ERRORNAME is nil, just return nil. 1634 ;; if ERRORNAME is nil, just return nil.
1760 (defun Info-extract-pointer (name &optional errorname) 1635 (defun Info-extract-pointer (name &optional errorname)
1761 (save-excursion 1636 (save-excursion
1762 (goto-char (point-min)) 1637 (goto-char (point-min))
1763 (forward-line 4) 1638 (forward-line 4)
2015 (setq item nil)))) 1890 (setq item nil))))
2016 (list item)))) 1891 (list item))))
2017 ;; there is a problem here in that if several menu items have the same 1892 ;; there is a problem here in that if several menu items have the same
2018 ;; name you can only go to the node of the first with this command. 1893 ;; name you can only go to the node of the first with this command.
2019 (Info-goto-node (Info-extract-menu-item menu-item) nil t)) 1894 (Info-goto-node (Info-extract-menu-item menu-item) nil t))
2020 1895
2021 (defun Info-extract-menu-item (menu-item &optional noerror) 1896 (defun Info-extract-menu-item (menu-item &optional noerror)
2022 (save-excursion 1897 (save-excursion
2023 (goto-char (point-min)) 1898 (goto-char (point-min))
2024 (if (let ((case-fold-search t)) 1899 (if (let ((case-fold-search t))
2025 (search-forward "\n* menu:" nil t)) 1900 (search-forward "\n* menu:" nil t))
2178 (while (>= (setq n (1- n)) 0) 2053 (while (>= (setq n (1- n)) 0)
2179 (if (pos-visible-in-window-p (point-min)) 2054 (if (pos-visible-in-window-p (point-min))
2180 (progn 2055 (progn
2181 (Info-global-prev) 2056 (Info-global-prev)
2182 (message "Node: %s" Info-current-node) 2057 (message "Node: %s" Info-current-node)
2183 (goto-char (point-max)) 2058 (sit-for 0)
2184 (recenter -1) 2059 ;;(scroll-up 1) ; work around bug in pos-visible-in-window-p
2185 (move-to-window-line 0)) 2060 ;;(scroll-down 1)
2061 (while (not (pos-visible-in-window-p (point-max)))
2062 (scroll-up)))
2186 (scroll-down))))) 2063 (scroll-down)))))
2187 2064
2188 (defun Info-scroll-prev (arg) 2065 (defun Info-scroll-prev (arg)
2189 (interactive "P") 2066 (interactive "P")
2190 (if Info-auto-advance 2067 (if Info-auto-advance
2191 (if (and (pos-visible-in-window-p (point-min)) 2068 (if (and (pos-visible-in-window-p (point-min))
2192 (not (eq Info-auto-advance t)) 2069 (not (eq Info-auto-advance t))
2193 (not (eq last-command this-command))) 2070 (not (eq last-command this-command)))
2194 (message "Hit %s again to go to previous node" 2071 (message "Hit %s again to go to previous node"
2195 (if (mouse-event-p last-command-event) 2072 (if (= last-command-char 0)
2196 "mouse button" 2073 "mouse button"
2197 (key-description (event-key last-command-event)))) 2074 (key-description (char-to-string last-command-char))))
2198 (Info-page-prev) 2075 (Info-page-prev)
2199 (setq this-command 'Info)) 2076 (setq this-command 'Info))
2200 (scroll-down arg))) 2077 (scroll-down arg)))
2201 2078
2202 (defun Info-index (topic) 2079 (defun Info-index (topic)
2364 ;;;###autoload 2241 ;;;###autoload
2365 (defun Info-elisp-ref (func) 2242 (defun Info-elisp-ref (func)
2366 "Look up an Emacs Lisp function in the Elisp manual in the Info system. 2243 "Look up an Emacs Lisp function in the Elisp manual in the Info system.
2367 This command is designed to be used whether you are already in Info or not." 2244 This command is designed to be used whether you are already in Info or not."
2368 (interactive (let ((fn (function-at-point)) 2245 (interactive (let ((fn (function-at-point))
2369 (enable-recursive-minibuffers t) 2246 (enable-recursive-minibuffers t)
2370 val) 2247 val)
2371 (setq val (completing-read 2248 (setq val (completing-read
2372 (format "Look up Emacs Lisp function%s: " 2249 (format "Look up Emacs Lisp function%s: "
2373 (if fn 2250 (if fn
2374 (format " (default %s)" fn) 2251 (format " (default %s)" fn)
2437 (setq bufs (cdr bufs)))) 2314 (setq bufs (cdr bufs))))
2438 (goto-char savept))))) 2315 (goto-char savept)))))
2439 2316
2440 (defvar Info-annotate-map nil 2317 (defvar Info-annotate-map nil
2441 "Local keymap used within `a' command of Info.") 2318 "Local keymap used within `a' command of Info.")
2442
2443 (if Info-annotate-map 2319 (if Info-annotate-map
2444 nil 2320 nil
2445 ;; (setq Info-annotate-map (nconc (make-sparse-keymap) text-mode-map)) 2321 ;; (setq Info-annotate-map (nconc (make-sparse-keymap) text-mode-map))
2446 (setq Info-annotate-map (copy-keymap text-mode-map)) 2322 (setq Info-annotate-map (copy-keymap text-mode-map))
2447 (define-key Info-annotate-map "\C-c\C-c" 'Info-cease-annotate)) 2323 (define-key Info-annotate-map "\C-c\C-c" 'Info-cease-annotate))
2736 (defun Info-mouse-track-double-click-hook (event click-count) 2612 (defun Info-mouse-track-double-click-hook (event click-count)
2737 "Handle double-clicks by turning pages, like the `gv' ghostscript viewer" 2613 "Handle double-clicks by turning pages, like the `gv' ghostscript viewer"
2738 (if (/= click-count 2) 2614 (if (/= click-count 2)
2739 ;; Return nil so any other hooks are performed. 2615 ;; Return nil so any other hooks are performed.
2740 nil 2616 nil
2741 (let* ((fw (face-width 'default)) 2617 (let* ((x (event-x-pixel event))
2742 (fh (face-height 'default)) 2618 (y (event-y-pixel event))
2743 (x (/ (event-x-pixel event) fw)) 2619 (w (window-pixel-width (event-window event)))
2744 (y (/ (event-y-pixel event) fw)) 2620 (h (window-pixel-height (event-window event)))
2745 (w (/ (window-pixel-width (event-window event)) fw)) 2621 (w/3 (/ w 3))
2746 (h (/ (window-pixel-height (event-window event)) fh)) 2622 (w/2 (/ w 2))
2747 (bx 3) 2623 (h/4 (/ h 4)))
2748 (by 2))
2749 (cond 2624 (cond
2750 ((<= y by) (Info-up) t) 2625 ;; In the top 1/4 and inside the middle 1/3
2751 ((>= y (- h by)) (Info-nth-menu-item 1) t) 2626 ((and (<= y h/4)
2752 ((<= x bx) (Info-prev) t) 2627 (and (>= x w/3) (<= x (+ w/3 w/3))))
2753 ((>= x (- w bx)) (Info-next) t) 2628 (Info-up)
2754 (t nil))))) 2629 t)
2630 ;; In the bottom 1/4 and inside the middle 1/3
2631 ((and (>= y (+ h/4 h/4 h/4))
2632 (and (>= x w/3) (<= x (+ w/3 w/3))))
2633 (Info-nth-menu-item 1)
2634 t)
2635 ;; In the lower 3/4 and the right 1/2
2636 ;; OR in the upper 1/4 and the right 1/3
2637 ((or (and (>= y h/4) (>= x w/2))
2638 (and (< y h/4) (>= x (+ w/3 w/3))))
2639 (Info-next)
2640 t)
2641 ;; In the lower 3/4 and the left 1/2
2642 ;; OR in the upper 1/4 and the left 1/3
2643 ((or (and (>= y h/4) (< x w/2))
2644 (and (< y h/4) (<= x w/3)))
2645 (Info-prev)
2646 t)
2647 ;; This shouldn't happen.
2648 (t
2649 (error "event out of bounds: %s %s" x y))))))
2755 2650
2756 (defvar Info-mode-map nil 2651 (defvar Info-mode-map nil
2757 "Keymap containing Info commands.") 2652 "Keymap containing Info commands.")
2758
2759 (if Info-mode-map 2653 (if Info-mode-map
2760 nil 2654 nil
2761 (setq Info-mode-map (make-sparse-keymap)) 2655 (setq Info-mode-map (make-sparse-keymap))
2762 (suppress-keymap Info-mode-map) 2656 (suppress-keymap Info-mode-map)
2763 (define-key Info-mode-map "." 'beginning-of-buffer) 2657 (define-key Info-mode-map "." 'beginning-of-buffer)
2846 Space Scroll forward a full screen. DEL Scroll backward. 2740 Space Scroll forward a full screen. DEL Scroll backward.
2847 b Go to beginning of node. Meta-> Go to end of node. 2741 b Go to beginning of node. Meta-> Go to end of node.
2848 TAB Go to next cross-reference. Meta-TAB Go to previous ref. 2742 TAB Go to next cross-reference. Meta-TAB Go to previous ref.
2849 2743
2850 Mouse commands: 2744 Mouse commands:
2851 Left Button Set point (usual text-mode functionality) 2745 Left Button Set point.
2852 Middle Button Click on a highlighted node reference to go to it. 2746 Middle Button Click on a highlighted node reference to go to it.
2853 Right Button Pop up a menu of applicable Info commands. 2747 Right Button Pop up a menu of applicable Info commands.
2854
2855 Left Button Double Click in window edges:
2856 Top edge: Go up to the parent node, like `u'.
2857 Left edge: Go to the previous node, like `p'.
2858 Right edge: Go to the next node, like `n'.
2859 Bottom edge: Follow first menu item, like `1'.
2860 2748
2861 Advanced commands: 2749 Advanced commands:
2862 g Move to node, file, or annotation tag specified by name. 2750 g Move to node, file, or annotation tag specified by name.
2863 Examples: `g Rectangles' `g (Emacs)Rectangles' `g Emacs'. 2751 Examples: `g Rectangles' `g (Emacs)Rectangles' `g Emacs'.
2864 v Move to file, with filename completion. 2752 v Move to file, with filename completion.
2912 (run-hooks 'Info-mode-hook) 2800 (run-hooks 'Info-mode-hook)
2913 (Info-set-mode-line)) 2801 (Info-set-mode-line))
2914 2802
2915 (defvar Info-edit-map nil 2803 (defvar Info-edit-map nil
2916 "Local keymap used within `e' command of Info.") 2804 "Local keymap used within `e' command of Info.")
2917
2918 (if Info-edit-map 2805 (if Info-edit-map
2919 nil 2806 nil
2920 ;; XEmacs: remove FSF stuff 2807 ;; XEmacs: remove FSF stuff
2921 (setq Info-edit-map (make-sparse-keymap)) 2808 (setq Info-edit-map (make-sparse-keymap))
2922 (set-keymap-name Info-edit-map 'Info-edit-map) 2809 (set-keymap-name Info-edit-map 'Info-edit-map)
3052 (progn 2939 (progn
3053 (goto-char (match-end 0)) 2940 (goto-char (match-end 0))
3054 (while 2941 (while
3055 (looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?\n?") 2942 (looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?\n?")
3056 (goto-char (match-end 0)) 2943 (goto-char (match-end 0))
3057 (Info-highlight-region (match-beginning 1) (match-end 1) 2944 (Info-highlight-region (match-beginning 1) (match-end 1) 'info-xref))))
3058 'info-xref))))
3059 ;; Now get the xrefs in the body 2945 ;; Now get the xrefs in the body
3060 (goto-char (point-min)) 2946 (goto-char (point-min))
3061 (while (re-search-forward xref-regexp nil t) 2947 (while (re-search-forward xref-regexp nil t)
3062 (if (= (char-after (1- (match-beginning 0))) ?\") ; hack 2948 (if (= (char-after (1- (match-beginning 0))) ?\") ; hack
3063 nil 2949 nil
3064 (Info-highlight-region (match-beginning 1) (match-end 1) 2950 (Info-highlight-region (match-beginning 1) (match-end 1) 'info-xref)))
3065 'info-xref)))
3066 ;; then highlight the nodes in the menu. 2951 ;; then highlight the nodes in the menu.
3067 (goto-char (point-min)) 2952 (goto-char (point-min))
3068 (if (and (search-forward "\n* menu:" nil t)) 2953 (if (and (search-forward "\n* menu:" nil t))
3069 (while (re-search-forward 2954 (while (re-search-forward
3070 "^\\* \\([^:\t\n]*\\):?:[ \t\n]" nil t) 2955 "^\\* \\([^:\t\n]*\\):?:[ \t\n]" nil t)
3071 (Info-highlight-region (match-beginning 1) (match-end 1) 2956 (Info-highlight-region (match-beginning 1) (match-end 1) 'info-node)))
3072 'info-node)))
3073 (set-buffer-modified-p nil)))) 2957 (set-buffer-modified-p nil))))
3074 2958
3075 (defun Info-construct-menu (&optional event) 2959 (defun Info-construct-menu (&optional event)
3076 "Construct a menu of Info commands. 2960 "Construct a menu of Info commands.
3077 Adds an entry for the node at EVENT, or under point if EVENT is omitted. 2961 Adds an entry for the node at EVENT, or under point if EVENT is omitted.
3078 Used to construct the menubar submenu and popup menu." 2962 Used to construct the menubar submenu and popup menu."
3079 (or event (setq event (point))) 2963 (or event (setq event (point)))
3080 (let ((case-fold-search t) 2964 (let ((case-fold-search t)
3081 (xref-regexp (concat "\\*" 2965 (xref-regexp (concat "\\*"
3082 (regexp-quote Info-footnote-tag) 2966 (regexp-quote Info-footnote-tag)
3083 "[ \n\t]*\\([^:]*\\):")) 2967 "[ \n\t]*\\([^:]*\\):"))
3084 up-p prev-p next-p menu xrefs subnodes in) 2968 up-p prev-p next-p menu xrefs subnodes in)
3085 (save-excursion 2969 (save-excursion
3086 ;; `one-space' fixes "Notes:" xrefs that are split across lines. 2970 ;; `one-space' fixes "Notes:" xrefs that are split across lines.