aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuri Linkov2009-07-02 22:47:33 +0000
committerJuri Linkov2009-07-02 22:47:33 +0000
commit6a013a4918b1103b15d8cecd73a56e7c06bf8fe2 (patch)
tree5e17f02c36c82bb9dabbd6406e65a8a4f0136845
parentd04bc496debb1183a2a8b1cd6864cdb4799e044b (diff)
downloademacs-6a013a4918b1103b15d8cecd73a56e7c06bf8fe2.tar.gz
emacs-6a013a4918b1103b15d8cecd73a56e7c06bf8fe2.zip
Virtual Info files and nodes.
(Info-virtual-files, Info-virtual-nodes): New variables. (Info-current-node-virtual): New variable. (Info-virtual-file-p, Info-virtual-fun, Info-virtual-call): New functions. (Info-file-supports-index-cookies): Use Info-virtual-file-p to check for a virtual file instead of checking a fixed list of node names. (Info-find-file): Use Info-virtual-fun and Info-virtual-call instead of ad-hoc processing of "dir" and (apropos history toc). (Info-find-node-2): Use Info-virtual-fun and Info-virtual-call instead of ad-hoc processing of "dir" and (apropos history toc). Reread a file when moving from a virtual node. (add-to-list)<Info-virtual-files>: Add "\\`dir\\'". (Info-directory-toc-nodes, Info-directory-find-file) (Info-directory-find-node): New functions. (add-to-list)<Info-virtual-files>: Add "\\`\\*History\\*\\'". (Info-history): Move part of code to `Info-history-find-node'. (Info-history-toc-nodes, Info-history-find-file) (Info-history-find-node): New functions. (add-to-list)<Info-virtual-nodes>: Add "\\`\\*TOC\\*\\'". (Info-toc): Move part of code to `Info-toc-find-node'. (Info-toc-find-node): New function. (Info-toc-insert): Renamed from `Info-insert-toc'. Don't insert the current Info file name to references because now the node "*TOC*" belongs to the same Info manual. (Info-toc-build): Renamed from `Info-build-toc'. (Info-toc-nodes): Rename input argument `file' to `filename'. Use Info-virtual-fun, Info-virtual-call and Info-virtual-file-p instead of ad-hoc processing of ("dir" apropos history toc). (Info-index-nodes): Use Info-virtual-file-p to check for a virtual file instead of checking a fixed list of node names. (Info-index-node): Add check for `Info-current-node-virtual'. Raise `save-match-data' higher up the tree to contain `search-forward' too (bug fix). (add-to-list)<Info-virtual-nodes>: Add "\\`\\*Index.*\\*\\'". (Info-virtual-index-nodes): New variable. (Info-virtual-index-find-node, Info-virtual-index): New functions. (add-to-list)<Info-virtual-files>: Add "\\`\\*Apropos\\*\\'". (Info-apropos-file, Info-apropos-nodes): New variables. (Info-apropos-toc-nodes, Info-apropos-find-file) (Info-apropos-find-node, Info-apropos-matches): New functions. (info-apropos): Move part of code to `Info-apropos-find-node' and `Info-apropos-matches'. (Info-mode-map): Bind "I" to `Info-virtual-index'. (Info-desktop-buffer-misc-data): Use Info-virtual-file-p to check for a virtual file instead of checking a fixed list of node names.
-rw-r--r--lisp/info.el707
1 files changed, 479 insertions, 228 deletions
diff --git a/lisp/info.el b/lisp/info.el
index e9e2b4225f3..03618cc098d 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -328,6 +328,54 @@ If number, the point is moved to the corresponding line.")
328 328
329(defvar Info-standalone nil 329(defvar Info-standalone nil
330 "Non-nil if Emacs was started solely as an Info browser.") 330 "Non-nil if Emacs was started solely as an Info browser.")
331
332(defvar Info-virtual-files nil
333 "List of definitions of virtual Info files.
334Each element of the list has the format (FILENAME (OPERATION . HANDLER) ...)
335where FILENAME is a regexp that matches a class of virtual Info file names.
336It should be carefully chosen to not cause file name clashes with
337existing file names. OPERATION is one of the following operation
338symbols `find-file', `find-node', `toc-nodes' that define what HANDLER
339function to call instead of calling the default corresponding function
340to override it.")
341
342(defvar Info-virtual-nodes nil
343 "List of definitions of virtual Info nodes.
344Each element of the list has the format (NODENAME (OPERATION . HANDLER) ...)
345where NODENAME is a regexp that matches a class of virtual Info node names.
346It should be carefully chosen to not cause node name clashes with
347existing node names. OPERATION is one of the following operation
348symbols `find-node' that define what HANDLER
349function to call instead of calling the default corresponding function
350to override it.")
351
352(defvar Info-current-node-virtual nil
353 "Non-nil if the current Info node is virtual.")
354
355(defun Info-virtual-file-p (filename)
356 "Check if Info file FILENAME is virtual."
357 (Info-virtual-fun 'find-file filename nil))
358
359(defun Info-virtual-fun (op filename nodename)
360 "Find a function that handles operations on virtual manuals.
361OP is an operation symbol (`find-file', `find-node' or `toc-nodes'),
362FILENAME is a virtual Info file name, NODENAME is a virtual Info
363node name. Return a function found either in `Info-virtual-files'
364or `Info-virtual-nodes'."
365 (or (and (stringp filename) ; some legacy code can still use a symbol
366 (cdr-safe (assoc op (assoc-default filename
367 Info-virtual-files
368 'string-match))))
369 (and (stringp nodename) ; some legacy code can still use a symbol
370 (cdr-safe (assoc op (assoc-default nodename
371 Info-virtual-nodes
372 'string-match))))))
373
374(defun Info-virtual-call (virtual-fun &rest args)
375 "Call a function that handles operations on virtual manuals."
376 (when (functionp virtual-fun)
377 (or (apply virtual-fun args) t)))
378
331 379
332(defvar Info-suffix-list 380(defvar Info-suffix-list
333 ;; The MS-DOS list should work both when long file names are 381 ;; The MS-DOS list should work both when long file names are
@@ -481,7 +529,7 @@ in `Info-file-supports-index-cookies-list'."
481 (or (assoc file Info-file-supports-index-cookies-list) 529 (or (assoc file Info-file-supports-index-cookies-list)
482 ;; Skip virtual Info files 530 ;; Skip virtual Info files
483 (and (or (not (stringp file)) 531 (and (or (not (stringp file))
484 (member file '("dir" apropos history toc))) 532 (Info-virtual-file-p file))
485 (setq Info-file-supports-index-cookies-list 533 (setq Info-file-supports-index-cookies-list
486 (cons (cons file nil) Info-file-supports-index-cookies-list))) 534 (cons (cons file nil) Info-file-supports-index-cookies-list)))
487 (save-excursion 535 (save-excursion
@@ -660,59 +708,58 @@ Optional second argument NOERROR, if t, means if file is not found
660just return nil (no error)." 708just return nil (no error)."
661 ;; Convert filename to lower case if not found as specified. 709 ;; Convert filename to lower case if not found as specified.
662 ;; Expand it. 710 ;; Expand it.
663 (if (stringp filename) 711 (cond
664 (let (temp temp-downcase found) 712 ((Info-virtual-call
665 (setq filename (substitute-in-file-name filename)) 713 (Info-virtual-fun 'find-file filename nil)
666 (cond 714 filename noerror))
667 ((string= (downcase filename) "dir") 715 ((stringp filename)
668 (setq found t)) 716 (let (temp temp-downcase found)
669 (t 717 (setq filename (substitute-in-file-name filename))
670 (let ((dirs (if (string-match "^\\./" filename) 718 (let ((dirs (if (string-match "^\\./" filename)
671 ;; If specified name starts with `./' 719 ;; If specified name starts with `./'
672 ;; then just try current directory. 720 ;; then just try current directory.
673 '("./") 721 '("./")
674 (if (file-name-absolute-p filename) 722 (if (file-name-absolute-p filename)
675 ;; No point in searching for an 723 ;; No point in searching for an
676 ;; absolute file name 724 ;; absolute file name
677 '(nil) 725 '(nil)
678 (if Info-additional-directory-list 726 (if Info-additional-directory-list
679 (append Info-directory-list 727 (append Info-directory-list
680 Info-additional-directory-list) 728 Info-additional-directory-list)
681 Info-directory-list))))) 729 Info-directory-list)))))
682 ;; Search the directory list for file FILENAME. 730 ;; Search the directory list for file FILENAME.
683 (while (and dirs (not found)) 731 (while (and dirs (not found))
684 (setq temp (expand-file-name filename (car dirs))) 732 (setq temp (expand-file-name filename (car dirs)))
685 (setq temp-downcase 733 (setq temp-downcase
686 (expand-file-name (downcase filename) (car dirs))) 734 (expand-file-name (downcase filename) (car dirs)))
687 ;; Try several variants of specified name. 735 ;; Try several variants of specified name.
688 (let ((suffix-list Info-suffix-list) 736 (let ((suffix-list Info-suffix-list)
689 (lfn (if (fboundp 'msdos-long-file-names) 737 (lfn (if (fboundp 'msdos-long-file-names)
690 (msdos-long-file-names) 738 (msdos-long-file-names)
691 t))) 739 t)))
692 (while (and suffix-list (not found)) 740 (while (and suffix-list (not found))
693 (cond ((info-file-exists-p 741 (cond ((info-file-exists-p
694 (info-insert-file-contents-1 742 (info-insert-file-contents-1
695 temp (car (car suffix-list)) lfn)) 743 temp (car (car suffix-list)) lfn))
696 (setq found temp)) 744 (setq found temp))
697 ((info-file-exists-p 745 ((info-file-exists-p
698 (info-insert-file-contents-1 746 (info-insert-file-contents-1
699 temp-downcase (car (car suffix-list)) lfn)) 747 temp-downcase (car (car suffix-list)) lfn))
700 (setq found temp-downcase)) 748 (setq found temp-downcase))
701 ((and (fboundp 'msdos-long-file-names) 749 ((and (fboundp 'msdos-long-file-names)
702 lfn 750 lfn
703 (info-file-exists-p 751 (info-file-exists-p
704 (info-insert-file-contents-1 752 (info-insert-file-contents-1
705 temp (car (car suffix-list)) nil))) 753 temp (car (car suffix-list)) nil)))
706 (setq found temp))) 754 (setq found temp)))
707 (setq suffix-list (cdr suffix-list)))) 755 (setq suffix-list (cdr suffix-list))))
708 (setq dirs (cdr dirs)))))) 756 (setq dirs (cdr dirs))))
709 (if found 757 (if found
710 (setq filename found) 758 (setq filename found)
711 (if noerror 759 (if noerror
712 (setq filename nil) 760 (setq filename nil)
713 (error "Info file %s does not exist" filename))) 761 (error "Info file %s does not exist" filename)))
714 filename) 762 filename))))
715 (and (member filename '(apropos history toc)) filename)))
716 763
717(defun Info-find-node (filename nodename &optional no-going-back) 764(defun Info-find-node (filename nodename &optional no-going-back)
718 "Go to an Info node specified as separate FILENAME and NODENAME. 765 "Go to an Info node specified as separate FILENAME and NODENAME.
@@ -862,68 +909,76 @@ a case-insensitive match is tried."
862 (setq Info-current-node nil) 909 (setq Info-current-node nil)
863 (unwind-protect 910 (unwind-protect
864 (let ((case-fold-search t) 911 (let ((case-fold-search t)
912 (virtual-fun (Info-virtual-fun 'find-node
913 (or filename Info-current-file)
914 nodename))
865 anchorpos) 915 anchorpos)
866 ;; Switch files if necessary 916 (cond
867 (or (null filename) 917 ((functionp virtual-fun)
868 (equal Info-current-file filename) 918 (let ((filename (or filename Info-current-file)))
869 (let ((inhibit-read-only t)) 919 (setq buffer-file-name nil)
870 (setq Info-current-file nil 920 (setq buffer-read-only nil)
871 Info-current-subfile nil 921 (erase-buffer)
872 Info-current-file-completions nil 922 (setq Info-current-file filename)
873 buffer-file-name nil) 923 (Info-virtual-call virtual-fun filename nodename no-going-back)
874 (erase-buffer) 924 (set-marker Info-tag-table-marker nil)
875 (cond 925 (setq buffer-read-only t)
876 ((eq filename t) 926 (set-buffer-modified-p nil)
877 (Info-insert-dir)) 927 (set (make-local-variable 'Info-current-node-virtual) t)))
878 ((eq filename 'apropos) 928 ((not (and
879 (insert-buffer-substring " *info-apropos*")) 929 ;; Reread a file when moving from a virtual node.
880 ((eq filename 'history) 930 (not Info-current-node-virtual)
881 (insert-buffer-substring " *info-history*")) 931 (or (null filename)
882 ((eq filename 'toc) 932 (equal Info-current-file filename))))
883 (insert-buffer-substring " *info-toc*")) 933 ;; Switch files if necessary
884 (t 934 (let ((inhibit-read-only t))
885 (info-insert-file-contents filename nil) 935 (if (and Info-current-node-virtual (null filename))
886 (setq default-directory (file-name-directory filename)))) 936 (setq filename Info-current-file))
887 (set-buffer-modified-p nil) 937 (setq Info-current-file nil
888 (set (make-local-variable 'Info-file-supports-index-cookies) 938 Info-current-subfile nil
889 (Info-file-supports-index-cookies filename)) 939 Info-current-file-completions nil
890 940 buffer-file-name nil)
891 ;; See whether file has a tag table. Record the location if yes. 941 (erase-buffer)
892 (goto-char (point-max)) 942 (info-insert-file-contents filename nil)
893 (forward-line -8) 943 (setq default-directory (file-name-directory filename))
894 ;; Use string-equal, not equal, to ignore text props. 944 (set-buffer-modified-p nil)
895 (if (not (or (string-equal nodename "*") 945 (set (make-local-variable 'Info-file-supports-index-cookies)
896 (not 946 (Info-file-supports-index-cookies filename))
897 (search-forward "\^_\nEnd tag table\n" nil t)))) 947
898 (let (pos) 948 ;; See whether file has a tag table. Record the location if yes.
899 ;; We have a tag table. Find its beginning. 949 (goto-char (point-max))
900 ;; Is this an indirect file? 950 (forward-line -8)
901 (search-backward "\nTag table:\n") 951 ;; Use string-equal, not equal, to ignore text props.
902 (setq pos (point)) 952 (if (not (or (string-equal nodename "*")
903 (if (save-excursion 953 (not
904 (forward-line 2) 954 (search-forward "\^_\nEnd tag table\n" nil t))))
905 (looking-at "(Indirect)\n")) 955 (let (pos)
906 ;; It is indirect. Copy it to another buffer 956 ;; We have a tag table. Find its beginning.
907 ;; and record that the tag table is in that buffer. 957 ;; Is this an indirect file?
908 (let ((buf (current-buffer)) 958 (search-backward "\nTag table:\n")
909 (tagbuf 959 (setq pos (point))
910 (or Info-tag-table-buffer 960 (if (save-excursion
911 (generate-new-buffer " *info tag table*")))) 961 (forward-line 2)
912 (setq Info-tag-table-buffer tagbuf) 962 (looking-at "(Indirect)\n"))
913 (with-current-buffer tagbuf 963 ;; It is indirect. Copy it to another buffer
914 (buffer-disable-undo (current-buffer)) 964 ;; and record that the tag table is in that buffer.
915 (setq case-fold-search t) 965 (let ((buf (current-buffer))
916 (erase-buffer) 966 (tagbuf
917 (insert-buffer-substring buf)) 967 (or Info-tag-table-buffer
918 (set-marker Info-tag-table-marker 968 (generate-new-buffer " *info tag table*"))))
919 (match-end 0) tagbuf)) 969 (setq Info-tag-table-buffer tagbuf)
920 (set-marker Info-tag-table-marker pos))) 970 (with-current-buffer tagbuf
921 (set-marker Info-tag-table-marker nil)) 971 (buffer-disable-undo (current-buffer))
922 (setq Info-current-file 972 (setq case-fold-search t)
923 (cond 973 (erase-buffer)
924 ((eq filename t) "dir") 974 (insert-buffer-substring buf))
925 (t filename))) 975 (set-marker Info-tag-table-marker
926 )) 976 (match-end 0) tagbuf))
977 (set-marker Info-tag-table-marker pos)))
978 (set-marker Info-tag-table-marker nil))
979 (setq Info-current-file filename)
980 )))
981
927 ;; Use string-equal, not equal, to ignore text props. 982 ;; Use string-equal, not equal, to ignore text props.
928 (if (string-equal nodename "*") 983 (if (string-equal nodename "*")
929 (progn (setq Info-current-node nodename) 984 (progn (setq Info-current-node nodename)
@@ -1998,6 +2053,26 @@ If SAME-FILE is non-nil, do not move to a different Info file."
1998 (Info-find-node filename nodename) 2053 (Info-find-node filename nodename)
1999 (setq Info-history-forward history-forward) 2054 (setq Info-history-forward history-forward)
2000 (goto-char opoint))) 2055 (goto-char opoint)))
2056
2057(add-to-list 'Info-virtual-files
2058 '("\\`dir\\'"
2059 (toc-nodes . Info-directory-toc-nodes)
2060 (find-file . Info-directory-find-file)
2061 (find-node . Info-directory-find-node)
2062 ))
2063
2064(defun Info-directory-toc-nodes (filename)
2065 "Directory-specific implementation of Info-directory-toc-nodes."
2066 `(,filename
2067 ("Top" nil nil nil)))
2068
2069(defun Info-directory-find-file (filename &optional noerror)
2070 "Directory-specific implementation of Info-find-file."
2071 filename)
2072
2073(defun Info-directory-find-node (filename nodename &optional no-going-back)
2074 "Directory-specific implementation of Info-find-node-2."
2075 (Info-insert-dir))
2001 2076
2002;;;###autoload 2077;;;###autoload
2003(defun Info-directory () 2078(defun Info-directory ()
@@ -2005,72 +2080,88 @@ If SAME-FILE is non-nil, do not move to a different Info file."
2005 (interactive) 2080 (interactive)
2006 (Info-find-node "dir" "top")) 2081 (Info-find-node "dir" "top"))
2007 2082
2083(add-to-list 'Info-virtual-files
2084 '("\\`\\*History\\*\\'"
2085 (toc-nodes . Info-history-toc-nodes)
2086 (find-file . Info-history-find-file)
2087 (find-node . Info-history-find-node)
2088 ))
2089
2090(defun Info-history-toc-nodes (filename)
2091 "History-specific implementation of Info-history-toc-nodes."
2092 `(,filename
2093 ("Top" nil nil nil)))
2094
2095(defun Info-history-find-file (filename &optional noerror)
2096 "History-specific implementation of Info-find-file."
2097 filename)
2098
2099(defun Info-history-find-node (filename nodename &optional no-going-back)
2100 "History-specific implementation of Info-find-node-2."
2101 (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n"
2102 (or filename Info-current-file) nodename))
2103 (insert "Recently Visited Nodes\n")
2104 (insert "**********************\n\n")
2105 (insert "* Menu:\n\n")
2106 (let ((hl (delete '("*History*" "Top") Info-history-list)))
2107 (while hl
2108 (let ((file (nth 0 (car hl)))
2109 (node (nth 1 (car hl))))
2110 (if (stringp file)
2111 (insert "* " node ": ("
2112 (propertize (or (file-name-directory file) "") 'invisible t)
2113 (file-name-nondirectory file)
2114 ")" node ".\n")))
2115 (setq hl (cdr hl)))))
2116
2008(defun Info-history () 2117(defun Info-history ()
2009 "Go to a node with a menu of visited nodes." 2118 "Go to a node with a menu of visited nodes."
2010 (interactive) 2119 (interactive)
2011 (let ((curr-file Info-current-file) 2120 (Info-find-node "*History*" "Top")
2012 (curr-node Info-current-node) 2121 (Info-next-reference)
2013 p) 2122 (Info-next-reference))
2014 (with-current-buffer (get-buffer-create " *info-history*") 2123
2015 (let ((inhibit-read-only t)) 2124(add-to-list 'Info-virtual-nodes
2016 (erase-buffer) 2125 '("\\`\\*TOC\\*\\'"
2017 (goto-char (point-min)) 2126 (find-node . Info-toc-find-node)
2018 (insert "\n\^_\nFile: history, Node: Top, Up: (dir)\n\n") 2127 ))
2019 (insert "Recently Visited Nodes\n**********************\n\n") 2128
2020 (insert "* Menu:\n\n") 2129(defun Info-toc-find-node (filename nodename &optional no-going-back)
2021 (let ((hl (delete '("history" "Top") Info-history-list))) 2130 "Toc-specific implementation of Info-find-node-2."
2022 (while hl 2131 (let* ((curr-file (substring-no-properties (or filename Info-current-file)))
2023 (let ((file (nth 0 (car hl))) 2132 (curr-node (substring-no-properties (or nodename Info-current-node)))
2024 (node (nth 1 (car hl)))) 2133 (node-list (Info-toc-nodes curr-file)))
2025 (if (and (equal file curr-file) 2134 (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
2026 (equal node curr-node)) 2135 curr-file curr-node))
2027 (setq p (point))) 2136 (insert "Table of Contents\n")
2028 (if (stringp file) 2137 (insert "*****************\n\n")
2029 (insert "* " node ": (" 2138 (insert "*Note Top::\n")
2030 (propertize (or (file-name-directory file) "") 'invisible t) 2139 (Info-toc-insert
2031 (file-name-nondirectory file) 2140 (nth 3 (assoc "Top" node-list)) ; get Top nodes
2032 ")" node ".\n"))) 2141 node-list 0 curr-file)
2033 (setq hl (cdr hl)))))) 2142 (unless (bobp)
2034 (Info-find-node 'history "Top") 2143 (let ((Info-hide-note-references 'hide)
2035 (goto-char (or p (point-min))))) 2144 (Info-fontify-visited-nodes nil))
2145 (setq Info-current-file filename Info-current-node "*TOC*")
2146 (goto-char (point-min))
2147 (narrow-to-region (or (re-search-forward "\n[\^_\f]\n" nil t)
2148 (point-min))
2149 (point-max))
2150 (Info-fontify-node)
2151 (widen)))))
2036 2152
2037(defun Info-toc () 2153(defun Info-toc ()
2038 "Go to a node with table of contents of the current Info file. 2154 "Go to a node with table of contents of the current Info file.
2039Table of contents is created from the tree structure of menus." 2155Table of contents is created from the tree structure of menus."
2040 (interactive) 2156 (interactive)
2041 (if (stringp Info-current-file) 2157 (Info-find-node Info-current-file "*TOC*")
2042 (let ((curr-file (substring-no-properties Info-current-file)) 2158 (let ((prev-node (nth 1 (car Info-history))) p)
2043 (curr-node (substring-no-properties Info-current-node)) 2159 (goto-char (point-min))
2044 p) 2160 (if (setq p (search-forward (concat "*Note " prev-node ":") nil t))
2045 (with-current-buffer (get-buffer-create " *info-toc*") 2161 (setq p (- p (length prev-node) 2)))
2046 (let ((inhibit-read-only t) 2162 (goto-char (or p (point-min)))))
2047 (node-list (Info-toc-nodes curr-file)))
2048 (erase-buffer)
2049 (goto-char (point-min))
2050 (insert "\n\^_\nFile: toc, Node: Top, Up: (dir)\n\n")
2051 (insert "Table of Contents\n*****************\n\n")
2052 (insert "*Note Top: (" curr-file ")Top.\n")
2053 (Info-insert-toc
2054 (nth 3 (assoc "Top" node-list)) ; get Top nodes
2055 node-list 0 curr-file))
2056 (if (not (bobp))
2057 (let ((Info-hide-note-references 'hide)
2058 (Info-fontify-visited-nodes nil))
2059 (Info-mode)
2060 (setq Info-current-file 'toc Info-current-node "Top")
2061 (goto-char (point-min))
2062 (narrow-to-region (or (re-search-forward "\n[\^_\f]\n" nil t)
2063 (point-min))
2064 (point-max))
2065 (Info-fontify-node)
2066 (widen)))
2067 (goto-char (point-min))
2068 (if (setq p (search-forward (concat "*Note " curr-node ":") nil t))
2069 (setq p (- p (length curr-node) 2))))
2070 (Info-find-node 'toc "Top")
2071 (goto-char (or p (point-min))))))
2072 2163
2073(defun Info-insert-toc (nodes node-list level curr-file) 2164(defun Info-toc-insert (nodes node-list level curr-file)
2074 "Insert table of contents with references to nodes." 2165 "Insert table of contents with references to nodes."
2075 (let ((section "Top")) 2166 (let ((section "Top"))
2076 (while nodes 2167 (while nodes
@@ -2078,11 +2169,11 @@ Table of contents is created from the tree structure of menus."
2078 (unless (member (nth 2 node) (list nil section)) 2169 (unless (member (nth 2 node) (list nil section))
2079 (insert (setq section (nth 2 node)) "\n")) 2170 (insert (setq section (nth 2 node)) "\n"))
2080 (insert (make-string level ?\t)) 2171 (insert (make-string level ?\t))
2081 (insert "*Note " (car nodes) ": (" curr-file ")" (car nodes) ".\n") 2172 (insert "*Note " (car nodes) ":: \n")
2082 (Info-insert-toc (nth 3 node) node-list (1+ level) curr-file) 2173 (Info-toc-insert (nth 3 node) node-list (1+ level) curr-file)
2083 (setq nodes (cdr nodes)))))) 2174 (setq nodes (cdr nodes))))))
2084 2175
2085(defun Info-build-toc (file) 2176(defun Info-toc-build (file)
2086 "Build table of contents from menus of Info FILE and its subfiles." 2177 "Build table of contents from menus of Info FILE and its subfiles."
2087 (with-temp-buffer 2178 (with-temp-buffer
2088 (let* ((file (and (stringp file) (Info-find-file file))) 2179 (let* ((file (and (stringp file) (Info-find-file file)))
@@ -2162,23 +2253,28 @@ where PARENT is the parent node extracted from the Up pointer,
2162SECTION is the section name in the Top node where this node is placed, 2253SECTION is the section name in the Top node where this node is placed,
2163CHILDREN is a list of child nodes extracted from the node menu.") 2254CHILDREN is a list of child nodes extracted from the node menu.")
2164 2255
2165(defun Info-toc-nodes (file) 2256(defun Info-toc-nodes (filename)
2166 "Return a node list of Info FILE with parent-children information. 2257 "Return a node list of Info FILENAME with parent-children information.
2167This information is cached in the variable `Info-toc-nodes' with the help 2258This information is cached in the variable `Info-toc-nodes' with the help
2168of the function `Info-build-toc'." 2259of the function `Info-toc-build'."
2169 (or file (setq file Info-current-file)) 2260 (cond
2170 (or (assoc file Info-toc-nodes) 2261 ((Info-virtual-call
2171 ;; Skip virtual Info files 2262 (Info-virtual-fun 'toc-nodes (or filename Info-current-file) nil)
2172 (and (or (not (stringp file)) 2263 filename))
2173 (member file '("dir" apropos history toc))) 2264 (t
2174 (push (cons file nil) Info-toc-nodes)) 2265 (or filename (setq filename Info-current-file))
2175 ;; Scan the entire manual and cache the result in Info-toc-nodes 2266 (or (assoc filename Info-toc-nodes)
2176 (let ((nodes (Info-build-toc file))) 2267 ;; Skip virtual Info files
2177 (push (cons file nodes) Info-toc-nodes) 2268 (and (or (not (stringp filename))
2178 nodes) 2269 (Info-virtual-file-p filename))
2179 ;; If there is an error, still add nil to the cache 2270 (push (cons filename nil) Info-toc-nodes))
2180 (push (cons file nil) Info-toc-nodes)) 2271 ;; Scan the entire manual and cache the result in Info-toc-nodes
2181 (cdr (assoc file Info-toc-nodes))) 2272 (let ((nodes (Info-toc-build filename)))
2273 (push (cons filename nodes) Info-toc-nodes)
2274 nodes)
2275 ;; If there is an error, still add nil to the cache
2276 (push (cons filename nil) Info-toc-nodes))
2277 (cdr (assoc filename Info-toc-nodes)))))
2182 2278
2183 2279
2184(defun Info-follow-reference (footnotename &optional fork) 2280(defun Info-follow-reference (footnotename &optional fork)
@@ -2792,7 +2888,7 @@ following nodes whose names also contain the word \"Index\"."
2792 (or (assoc file Info-index-nodes) 2888 (or (assoc file Info-index-nodes)
2793 ;; Skip virtual Info files 2889 ;; Skip virtual Info files
2794 (and (or (not (stringp file)) 2890 (and (or (not (stringp file))
2795 (member file '("dir" apropos history toc))) 2891 (Info-virtual-file-p file))
2796 (setq Info-index-nodes (cons (cons file nil) Info-index-nodes))) 2892 (setq Info-index-nodes (cons (cons file nil) Info-index-nodes)))
2797 (if (Info-file-supports-index-cookies file) 2893 (if (Info-file-supports-index-cookies file)
2798 ;; Find nodes with index cookie 2894 ;; Find nodes with index cookie
@@ -2860,21 +2956,22 @@ following nodes whose names also contain the word \"Index\"."
2860If NODE is nil, check the current Info node. 2956If NODE is nil, check the current Info node.
2861If FILE is nil, check the current Info file." 2957If FILE is nil, check the current Info file."
2862 (or file (setq file Info-current-file)) 2958 (or file (setq file Info-current-file))
2863 (if (or (and node (not (equal node Info-current-node))) 2959 (if (and (or (and node (not (equal node Info-current-node)))
2864 (assoc file Info-index-nodes)) 2960 (assoc file Info-index-nodes))
2961 (not Info-current-node-virtual))
2865 (member (or node Info-current-node) (Info-index-nodes file)) 2962 (member (or node Info-current-node) (Info-index-nodes file))
2866 ;; Don't search all index nodes if request is only for the current node 2963 ;; Don't search all index nodes if request is only for the current node
2867 ;; and file is not in the cache of index nodes 2964 ;; and file is not in the cache of index nodes
2868 (if (Info-file-supports-index-cookies file) 2965 (save-match-data
2869 (save-excursion 2966 (if (Info-file-supports-index-cookies file)
2870 (goto-char (+ (or (save-excursion 2967 (save-excursion
2871 (search-backward "\n\^_" nil t)) 2968 (goto-char (+ (or (save-excursion
2872 (point-min)) 2)) 2969 (search-backward "\n\^_" nil t))
2873 (search-forward "\0\b[index\0\b]" 2970 (point-min)) 2))
2874 (or (save-excursion 2971 (search-forward "\0\b[index\0\b]"
2875 (search-forward "\n\^_" nil t)) 2972 (or (save-excursion
2876 (point-max)) t)) 2973 (search-forward "\n\^_" nil t))
2877 (save-match-data 2974 (point-max)) t))
2878 (string-match "\\<Index\\>" (or node Info-current-node "")))))) 2975 (string-match "\\<Index\\>" (or node Info-current-node ""))))))
2879 2976
2880(defun Info-goto-index () 2977(defun Info-goto-index ()
@@ -3000,11 +3097,163 @@ Give an empty topic name to go to the Index node itself."
3000 (Info-find-index-name (match-string 1 name)))) 3097 (Info-find-index-name (match-string 1 name))))
3001 (progn (beginning-of-line) t) ;; non-nil for recursive call 3098 (progn (beginning-of-line) t) ;; non-nil for recursive call
3002 (goto-char (point-min))))) 3099 (goto-char (point-min)))))
3003 3100
3004;;;###autoload 3101(add-to-list 'Info-virtual-nodes
3005(defun info-apropos (string) 3102 '("\\`\\*Index.*\\*\\'"
3006 "Grovel indices of all known Info files on your system for STRING. 3103 (find-node . Info-virtual-index-find-node)
3007Build a menu of the possible matches." 3104 ))
3105
3106(defvar Info-virtual-index-nodes nil
3107 "Alist of cached matched index search nodes.
3108Each element is ((FILENAME . TOPIC) MATCHES) where
3109FILENAME is the file name of the manual,
3110TOPIC is the search string given as an argument to `Info-virtual-index',
3111MATCHES is a list of index matches found by `Info-index'.")
3112
3113(defun Info-virtual-index-find-node (filename nodename &optional no-going-back)
3114 "Index-specific implementation of Info-find-node-2."
3115 ;; Generate Index-like menu of matches
3116 (if (string-match "^\\*Index for `\\(.+\\)'\\*$" nodename)
3117 ;; Generate Index-like menu of matches
3118 (let* ((topic (match-string 1 nodename))
3119 (matches (cdr (assoc (cons (or filename Info-current-file) topic)
3120 Info-virtual-index-nodes))))
3121 (insert (format "\n\^_\nFile: %s, Node: %s, Up: *Index*\n\n"
3122 (or filename Info-current-file) nodename))
3123 (insert "Info Virtual Index\n")
3124 (insert "******************\n\n")
3125 (insert "Index entries that match `" topic "':\n\n")
3126 (insert "\0\b[index\0\b]\n")
3127 (if (null matches)
3128 (insert "No matches found.\n")
3129 (insert "* Menu:\n\n")
3130 (dolist (entry matches)
3131 (insert (format "* %-38s %s.%s\n"
3132 (format "%s [%s]:" (nth 0 entry) (nth 2 entry))
3133 (nth 1 entry)
3134 (if (nth 3 entry)
3135 (format " (line %s)" (nth 3 entry))
3136 ""))))))
3137 ;; Else, Generate a list of previous search results
3138 (let ((nodes (reverse Info-virtual-index-nodes)))
3139 (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
3140 (or filename Info-current-file) nodename))
3141 (insert "Info Virtual Index\n")
3142 (insert "******************\n\n")
3143 (insert "This is a list of search results produced by\n"
3144 "`Info-virtual-index' for the current manual.\n\n")
3145 (insert "* Menu:\n\n")
3146 (dolist (nodeinfo nodes)
3147 (when (equal (car (nth 0 nodeinfo)) (or filename Info-current-file))
3148 (insert
3149 (format "* %-20s %s.\n"
3150 (format "*Index for `%s'*::" (cdr (nth 0 nodeinfo)))
3151 (cdr (nth 0 nodeinfo)))))))))
3152
3153(defun Info-virtual-index (topic)
3154 "Show a node with all lines in the index containing a string TOPIC.
3155Like `Info-index' but displays a node with index search results.
3156Give an empty topic name to go to the node with links to previous
3157search results."
3158 ;; `interactive' is a copy from `Info-index'
3159 (interactive
3160 (list
3161 (let ((completion-ignore-case t)
3162 (Info-complete-menu-buffer (clone-buffer))
3163 (Info-complete-nodes (Info-index-nodes))
3164 (Info-history-list nil))
3165 (if (equal Info-current-file "dir")
3166 (error "The Info directory node has no index; use m to select a manual"))
3167 (unwind-protect
3168 (with-current-buffer Info-complete-menu-buffer
3169 (Info-goto-index)
3170 (completing-read "Index topic: " 'Info-complete-menu-item))
3171 (kill-buffer Info-complete-menu-buffer)))))
3172 (if (equal topic "")
3173 (Info-find-node Info-current-file "*Index*")
3174 (unless (assoc (cons Info-current-file topic) Info-virtual-index-nodes)
3175 (let ((orignode Info-current-node)
3176 (ohist-list Info-history-list)
3177 nodename)
3178 ;; Reuse `Info-index' to set `Info-index-alternatives'.
3179 (Info-index topic)
3180 (push (cons (cons Info-current-file topic) Info-index-alternatives)
3181 Info-virtual-index-nodes)
3182 ;; Clean up unneccessary side-effects of `Info-index'.
3183 (setq Info-history-list ohist-list)
3184 (Info-goto-node orignode)
3185 (message "")))
3186 (Info-find-node Info-current-file (format "*Index for `%s'*" topic))))
3187
3188(add-to-list 'Info-virtual-files
3189 '("\\`\\*Apropos\\*\\'"
3190 (toc-nodes . Info-apropos-toc-nodes)
3191 (find-file . Info-apropos-find-file)
3192 (find-node . Info-apropos-find-node)
3193 ))
3194
3195(defvar Info-apropos-file "*Apropos*"
3196 "Info file name of the virtual manual for matches of `info-apropos'.")
3197
3198(defvar Info-apropos-nodes nil
3199 "Alist of cached apropos matched nodes.
3200Each element is (NODENAME STRING MATCHES) where
3201NODENAME is the name of the node that holds the search result,
3202STRING is the search string given as an argument to `info-apropos',
3203MATCHES is a list of index matches found by `Info-apropos-matches'.")
3204
3205(defun Info-apropos-toc-nodes (filename)
3206 "Apropos-specific implementation of Info-apropos-toc-nodes."
3207 (let ((nodes (mapcar 'car (reverse Info-apropos-nodes))))
3208 `(,filename
3209 ("Top" nil nil ,nodes)
3210 ,@(mapcar (lambda (node) `(,node "Top" nil nil)) nodes))))
3211
3212(defun Info-apropos-find-file (filename &optional noerror)
3213 "Apropos-specific implementation of Info-find-file."
3214 filename)
3215
3216(defun Info-apropos-find-node (filename nodename &optional no-going-back)
3217 "Apropos-specific implementation of Info-find-node-2."
3218 (if (equal nodename "Top")
3219 ;; Generate Top menu
3220 (let ((nodes (reverse Info-apropos-nodes)))
3221 (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n"
3222 Info-apropos-file nodename))
3223 (insert "Apropos Index\n")
3224 (insert "*************\n\n")
3225 (insert "This is a list of search results produced by `info-apropos'.\n\n")
3226 (insert "* Menu:\n\n")
3227 (dolist (nodeinfo nodes)
3228 (insert (format "* %-20s %s.\n"
3229 (format "%s::" (nth 0 nodeinfo))
3230 (nth 1 nodeinfo)))))
3231 ;; Else, Generate Index-like menu of matches
3232 (let* ((nodeinfo (assoc nodename Info-apropos-nodes))
3233 (matches (nth 2 nodeinfo)))
3234 (when matches
3235 (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
3236 Info-apropos-file nodename))
3237 (insert "Apropos Index\n")
3238 (insert "*************\n\n")
3239 (insert "Index entries that match `" (nth 1 nodeinfo) "':\n\n")
3240 (insert "\0\b[index\0\b]\n")
3241 (if (eq matches t)
3242 (insert "No matches found.\n")
3243 (insert "* Menu:\n\n")
3244 (dolist (entry matches)
3245 (insert (format "* %-38s (%s)%s.%s\n"
3246 (format "%s [%s]:" (nth 1 entry) (nth 0 entry))
3247 (nth 0 entry)
3248 (nth 2 entry)
3249 (if (nth 3 entry)
3250 (format " (line %s)" (nth 3 entry))
3251 "")))))))))
3252
3253(defun Info-apropos-matches (string)
3254 "Collect STRING matches from all known Info files on your system.
3255Return a list of matches where each element is in the format
3256\((FILENAME INDEXTEXT NODENAME LINENUMBER))."
3008 (interactive "sIndex apropos: ") 3257 (interactive "sIndex apropos: ")
3009 (unless (string= string "") 3258 (unless (string= string "")
3010 (let ((pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ \t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?" 3259 (let ((pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ \t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
@@ -3056,24 +3305,25 @@ Build a menu of the possible matches."
3056 (setq Info-history ohist 3305 (setq Info-history ohist
3057 Info-history-list ohist-list) 3306 Info-history-list ohist-list)
3058 (message "Searching indices...done") 3307 (message "Searching indices...done")
3059 (if (null matches) 3308 (or (nreverse matches) t))))
3060 (message "No matches found")
3061 (with-current-buffer (get-buffer-create " *info-apropos*")
3062 (erase-buffer)
3063 (insert "\n\^_\nFile: apropos, Node: Index, Up: (dir)\n")
3064 (insert "* Menu: \nNodes whose indices contain `" string "':\n\n")
3065 (dolist (entry (nreverse matches))
3066 (insert
3067 (format "* %-38s (%s)%s.%s\n"
3068 (concat (nth 1 entry) " [" (nth 0 entry) "]:")
3069 (nth 0 entry)
3070 (nth 2 entry)
3071 (if (nth 3 entry)
3072 (concat " (line " (nth 3 entry) ")")
3073 "")))))
3074 (Info-find-node 'apropos "Index")
3075 (setq Info-complete-cache nil)))))
3076 3309
3310;;;###autoload
3311(defun info-apropos (string)
3312 "Grovel indices of all known Info files on your system for STRING.
3313Build a menu of the possible matches."
3314 (interactive "sIndex apropos: ")
3315 (if (equal string "")
3316 (Info-find-node Info-apropos-file "Top")
3317 (let* ((nodes Info-apropos-nodes) nodename)
3318 (while (and nodes (not (equal string (nth 1 (car nodes)))))
3319 (setq nodes (cdr nodes)))
3320 (if nodes
3321 (Info-find-node Info-apropos-file (car (car nodes)))
3322 (setq nodename (format "Index for `%s'" string))
3323 (push (list nodename string (Info-apropos-matches string))
3324 Info-apropos-nodes)
3325 (Info-find-node Info-apropos-file nodename)))))
3326
3077(defun Info-undefined () 3327(defun Info-undefined ()
3078 "Make command be undefined in Info." 3328 "Make command be undefined in Info."
3079 (interactive) 3329 (interactive)
@@ -3248,6 +3498,7 @@ If FORK is non-nil, it is passed to `Info-goto-node'."
3248 (define-key map "g" 'Info-goto-node) 3498 (define-key map "g" 'Info-goto-node)
3249 (define-key map "h" 'Info-help) 3499 (define-key map "h" 'Info-help)
3250 (define-key map "i" 'Info-index) 3500 (define-key map "i" 'Info-index)
3501 (define-key map "I" 'Info-virtual-index)
3251 (define-key map "l" 'Info-history-back) 3502 (define-key map "l" 'Info-history-back)
3252 (define-key map "L" 'Info-history) 3503 (define-key map "L" 'Info-history)
3253 (define-key map "m" 'Info-menu) 3504 (define-key map "m" 'Info-menu)
@@ -3830,7 +4081,7 @@ the variable `Info-file-list-for-emacs'."
3830 (format "(%s)Top" 4081 (format "(%s)Top"
3831 (if (stringp Info-current-file) 4082 (if (stringp Info-current-file)
3832 (file-name-nondirectory Info-current-file) 4083 (file-name-nondirectory Info-current-file)
3833 ;; Can be `toc', `apropos', or even `history'. 4084 ;; Some legacy code can still use a symbol.
3834 Info-current-file))))) 4085 Info-current-file)))))
3835 (insert (if (bolp) "" " > ") 4086 (insert (if (bolp) "" " > ")
3836 (cond 4087 (cond
@@ -4414,7 +4665,7 @@ BUFFER is the buffer speedbar is requesting buttons for."
4414 4665
4415(defun Info-desktop-buffer-misc-data (desktop-dirname) 4666(defun Info-desktop-buffer-misc-data (desktop-dirname)
4416 "Auxiliary information to be saved in desktop file." 4667 "Auxiliary information to be saved in desktop file."
4417 (unless (member Info-current-file '(apropos history toc nil)) 4668 (unless (Info-virtual-file-p Info-current-file)
4418 (list Info-current-file Info-current-node))) 4669 (list Info-current-file Info-current-node)))
4419 4670
4420(defun Info-restore-desktop-buffer (desktop-buffer-file-name 4671(defun Info-restore-desktop-buffer (desktop-buffer-file-name