+\f
+(add-to-list 'Info-virtual-nodes
+ '("\\`\\*Index.*\\*\\'"
+ (find-node . Info-virtual-index-find-node)
+ (slow . t)
+ ))
+
+(defvar Info-virtual-index-nodes nil
+ "Alist of cached matched index search nodes.
+Each element is ((FILENAME . TOPIC) MATCHES) where
+FILENAME is the file name of the manual,
+TOPIC is the search string given as an argument to `Info-virtual-index',
+MATCHES is a list of index matches found by `Info-index'.")
+
+(defun Info-virtual-index-find-node (filename nodename &optional no-going-back)
+ "Index-specific implementation of Info-find-node-2."
+ ;; Generate Index-like menu of matches
+ (if (string-match "^\\*Index for `\\(.+\\)'\\*$" nodename)
+ ;; Generate Index-like menu of matches
+ (let* ((topic (match-string 1 nodename))
+ (matches (cdr (assoc (cons (or filename Info-current-file) topic)
+ Info-virtual-index-nodes))))
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: *Index*\n\n"
+ (or filename Info-current-file) nodename))
+ (insert "Info Virtual Index\n")
+ (insert "******************\n\n")
+ (insert "Index entries that match `" topic "':\n\n")
+ (insert "\0\b[index\0\b]\n")
+ (if (null matches)
+ (insert "No matches found.\n")
+ (insert "* Menu:\n\n")
+ (dolist (entry matches)
+ (insert (format "* %-38s %s.%s\n"
+ (format "%s [%s]:" (nth 0 entry) (nth 2 entry))
+ (nth 1 entry)
+ (if (nth 3 entry)
+ (format " (line %s)" (nth 3 entry))
+ ""))))))
+ ;; Else, Generate a list of previous search results
+ (let ((nodes (reverse Info-virtual-index-nodes)))
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
+ (or filename Info-current-file) nodename))
+ (insert "Info Virtual Index\n")
+ (insert "******************\n\n")
+ (insert "This is a list of search results produced by\n"
+ "`Info-virtual-index' for the current manual.\n\n")
+ (insert "* Menu:\n\n")
+ (dolist (nodeinfo nodes)
+ (when (equal (car (nth 0 nodeinfo)) (or filename Info-current-file))
+ (insert
+ (format "* %-20s %s.\n"
+ (format "*Index for `%s'*::" (cdr (nth 0 nodeinfo)))
+ (cdr (nth 0 nodeinfo)))))))))
+
+(defun Info-virtual-index (topic)
+ "Show a node with all lines in the index containing a string TOPIC.
+Like `Info-index' but displays a node with index search results.
+Give an empty topic name to go to the node with links to previous
+search results."
+ ;; `interactive' is a copy from `Info-index'
+ (interactive
+ (list
+ (let ((completion-ignore-case t)
+ (Info-complete-menu-buffer (clone-buffer))
+ (Info-complete-nodes (Info-index-nodes))
+ (Info-history-list nil))
+ (if (equal Info-current-file "dir")
+ (error "The Info directory node has no index; use m to select a manual"))
+ (unwind-protect
+ (with-current-buffer Info-complete-menu-buffer
+ (Info-goto-index)
+ (completing-read "Index topic: " 'Info-complete-menu-item))
+ (kill-buffer Info-complete-menu-buffer)))))
+ (if (equal topic "")
+ (Info-find-node Info-current-file "*Index*")
+ (unless (assoc (cons Info-current-file topic) Info-virtual-index-nodes)
+ (let ((orignode Info-current-node)
+ (ohist-list Info-history-list)
+ nodename)
+ ;; Reuse `Info-index' to set `Info-index-alternatives'.
+ (Info-index topic)
+ (push (cons (cons Info-current-file topic) Info-index-alternatives)
+ Info-virtual-index-nodes)
+ ;; Clean up unneccessary side-effects of `Info-index'.
+ (setq Info-history-list ohist-list)
+ (Info-goto-node orignode)
+ (message "")))
+ (Info-find-node Info-current-file (format "*Index for `%s'*" topic))))
+\f
+(add-to-list 'Info-virtual-files
+ '("\\`\\*Apropos\\*\\'"
+ (toc-nodes . Info-apropos-toc-nodes)
+ (find-file . Info-apropos-find-file)
+ (find-node . Info-apropos-find-node)
+ (slow . t)
+ ))
+
+(defvar Info-apropos-file "*Apropos*"
+ "Info file name of the virtual manual for matches of `info-apropos'.")
+
+(defvar Info-apropos-nodes nil
+ "Alist of cached apropos matched nodes.
+Each element is (NODENAME STRING MATCHES) where
+NODENAME is the name of the node that holds the search result,
+STRING is the search string given as an argument to `info-apropos',
+MATCHES is a list of index matches found by `Info-apropos-matches'.")
+
+(defun Info-apropos-toc-nodes (filename)
+ "Apropos-specific implementation of Info-apropos-toc-nodes."
+ (let ((nodes (mapcar 'car (reverse Info-apropos-nodes))))
+ `(,filename
+ ("Top" nil nil ,nodes)
+ ,@(mapcar (lambda (node) `(,node "Top" nil nil)) nodes))))
+
+(defun Info-apropos-find-file (filename &optional noerror)
+ "Apropos-specific implementation of Info-find-file."
+ filename)
+
+(defun Info-apropos-find-node (filename nodename &optional no-going-back)
+ "Apropos-specific implementation of Info-find-node-2."
+ (if (equal nodename "Top")
+ ;; Generate Top menu
+ (let ((nodes (reverse Info-apropos-nodes)))
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n"
+ Info-apropos-file nodename))
+ (insert "Apropos Index\n")
+ (insert "*************\n\n")
+ (insert "This is a list of search results produced by `info-apropos'.\n\n")
+ (insert "* Menu:\n\n")
+ (dolist (nodeinfo nodes)
+ (insert (format "* %-20s %s.\n"
+ (format "%s::" (nth 0 nodeinfo))
+ (nth 1 nodeinfo)))))
+ ;; Else, Generate Index-like menu of matches
+ (let* ((nodeinfo (assoc nodename Info-apropos-nodes))
+ (matches (nth 2 nodeinfo)))
+ (when matches
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
+ Info-apropos-file nodename))
+ (insert "Apropos Index\n")
+ (insert "*************\n\n")
+ (insert "Index entries that match `" (nth 1 nodeinfo) "':\n\n")
+ (insert "\0\b[index\0\b]\n")
+ (if (eq matches t)
+ (insert "No matches found.\n")
+ (insert "* Menu:\n\n")
+ (dolist (entry matches)
+ (insert (format "* %-38s (%s)%s.%s\n"
+ (format "%s [%s]:" (nth 1 entry) (nth 0 entry))
+ (nth 0 entry)
+ (nth 2 entry)
+ (if (nth 3 entry)
+ (format " (line %s)" (nth 3 entry))
+ "")))))))))
+
+(defun Info-apropos-matches (string)
+ "Collect STRING matches from all known Info files on your system.
+Return a list of matches where each element is in the format
+\((FILENAME INDEXTEXT NODENAME LINENUMBER))."