emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Virtual Info files and nodes


From: Juri Linkov
Subject: Virtual Info files and nodes
Date: Mon, 29 Jun 2009 00:28:38 +0300
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1.50 (x86_64-pc-linux-gnu)

I'd like to present a patch that properly implements virtual Info files
and nodes.  It plugs in to just three functions in the Info package and
provides an API to redefine these functions to dynamically generate
either a virtual file or a virtual node:

  Info-toc-nodes:   property `toc-nodes'
  Info-find-file:   property `find-file'
  Info-find-node-2: property `find-node'

Each class of virtual files or nodes should register itself either
to the `Info-virtual-files' or `Info-virtual-nodes' global variables.
The first element of a definition should be a regexp that matches
a class of virtual files or nodes, and the rest is an alist that
maps a property name to the overriding function name.  For instance,
a definition for the Apropos virtual file is:

  '("^\\*Apropos\\*$"
    (toc-nodes . Info-apropos-toc-nodes)
    (find-file . Info-apropos-find-file)
    (find-node . Info-apropos-find-node)
    ))

All this is like routes and controllers used in Web services to generate
dynamic HTML pages, where a Web server name corresponds to the Info file
name, and an URL path corresponds to the Info node name.  In a similar
way this feature generates dynamic Info pages instead of static Info pages.

This patch reimplements History, Table of Contents and Apropos, and also
adds new virtual nodes for the results of Info Index search:

1. Since History is a global list that refers to different visited Info
   manuals, it should be a virtual Info file instead of a node.

2. Unlike History, each Table of Contents belongs to one manual, so it
   should be a virtual node within the current Info manual.  It was
   incorrectly implemented as a virtual file that causes several problems,
   but the following patch fixes this by implementing a virtual node.

3. Apropos collects matches from all available Info manuals, so it is
   a virtual file with the Top node that refers to previous results.

4. Index search collects index entries from one Info manuals so it provides
   a virtual node for each search string and a separate virtual node
   with references to virtual nodes with previous results.
   A new keybinding `I' reads a string and displays a virtual node with
   index search matches.  And `I RET' with an empty string displays
   a virtual node with a list of previous results.

This patch leaves the processing of normal static Info manuals unaffected.

Index: lisp/info.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/info.el,v
retrieving revision 1.559
diff -c -w -b -r1.559 info.el
*** lisp/info.el        23 May 2009 23:31:52 -0000      1.559
--- lisp/info.el        28 Jun 2009 21:27:28 -0000
***************
*** 329,334 ****
--- 329,381 ----
  (defvar Info-standalone nil
    "Non-nil if Emacs was started solely as an Info browser.")
  
+ (defvar Info-virtual-files nil
+   "List of definitions of virtual Info files.
+ Each element of the list has the format (FILENAME (OPERATION . HANDLER) ...)
+ where FILENAME is a regexp that matches a class of virtual Info file names.
+ It should be carefully choosen to not cause file name clashes with
+ real file names.  OPERATION is one of the following operation symbols
+ `find-file', `find-node', `toc-nodes' that define what HANDLER
+ function to call instead of calling the default corresponding function
+ to override it.")
+ 
+ (defvar Info-virtual-nodes nil
+   "List of definitions of virtual Info nodes.
+ Each element of the list has the format (NODENAME (OPERATION . HANDLER) ...)
+ where NODENAME is a regexp that matches a class of virtual Info node names.
+ It should be carefully choosen to not cause node name clashes with
+ real node names.  OPERATION is one of the following operation symbols
+ `find-node' that define what HANDLER function to call instead of
+ calling the default corresponding function to override it.")
+ 
+ (defvar Info-current-node-virtual nil
+   "Non-nil if the current Info node is virtual.")
+ 
+ (defun Info-virtual-file (filename)
+   "Return a definition of the virtual Info file FILENAME."
+   (and (stringp filename)
+        (assoc-default filename Info-virtual-files 'string-match)))
+ 
+ (defun Info-virtual-node (nodename)
+   "Return a definition of the virtual Info node NODENAME."
+   (and (stringp nodename)
+        (assoc-default nodename Info-virtual-nodes 'string-match)))
+ 
+ (defun Info-virtual-fun (op filename nodename)
+   "Find a function that handles operations on virtual manuals.
+ OP is an operation symbol (`find-file', `find-node' or `toc-nodes'),
+ FILENAME is a virtual Info file name, NODENAME is a virtual Info
+ node name.  Return a function found either in `Info-virtual-files'
+ or `Info-virtual-nodes'."
+   (or (cdr-safe (assoc op (Info-virtual-file filename)))
+       (cdr-safe (assoc op (Info-virtual-node nodename)))))
+ 
+ (defun Info-virtual-call (virtual-fun &rest args)
+   "Call a function that handles operations on virtual manuals."
+   (when (functionp virtual-fun)
+     (or (apply virtual-fun args) t)))
+ 
+ 
  (defvar Info-suffix-list
    ;; The MS-DOS list should work both when long file names are
    ;; supported (Windows 9X), and when only 8+3 file names are available.
***************
*** 481,487 ****
    (or (assoc file Info-file-supports-index-cookies-list)
        ;; Skip virtual Info files
        (and (or (not (stringp file))
!              (member file '("dir" apropos history toc)))
             (setq Info-file-supports-index-cookies-list
                 (cons (cons file nil) Info-file-supports-index-cookies-list)))
        (save-excursion
--- 528,535 ----
    (or (assoc file Info-file-supports-index-cookies-list)
        ;; Skip virtual Info files
        (and (or (not (stringp file))
!              (Info-virtual-file file)
!              (member file '("dir")))
             (setq Info-file-supports-index-cookies-list
                 (cons (cons file nil) Info-file-supports-index-cookies-list)))
        (save-excursion
***************
*** 660,666 ****
  just return nil (no error)."
    ;; Convert filename to lower case if not found as specified.
    ;; Expand it.
!   (if (stringp filename)
        (let (temp temp-downcase found)
          (setq filename (substitute-in-file-name filename))
        (cond
--- 708,718 ----
  just return nil (no error)."
    ;; Convert filename to lower case if not found as specified.
    ;; Expand it.
!   (cond
!    ((Info-virtual-call
!      (Info-virtual-fun 'find-file filename nil)
!      filename noerror))
!    ((stringp filename)
      (let (temp temp-downcase found)
        (setq filename (substitute-in-file-name filename))
        (cond
***************
*** 711,718 ****
            (if noerror
                (setq filename nil)
              (error "Info file %s does not exist" filename)))
!         filename)
!     (and (member filename '(apropos history toc)) filename)))
  
  (defun Info-find-node (filename nodename &optional no-going-back)
    "Go to an Info node specified as separate FILENAME and NODENAME.
--- 763,769 ----
        (if noerror
            (setq filename nil)
          (error "Info file %s does not exist" filename)))
!       filename))))
  
  (defun Info-find-node (filename nodename &optional no-going-back)
    "Go to an Info node specified as separate FILENAME and NODENAME.
***************
*** 862,872 ****
    (setq Info-current-node nil)
    (unwind-protect
        (let ((case-fold-search t)
            anchorpos)
!         ;; Switch files if necessary
          (or (null filename)
!             (equal Info-current-file filename)
              (let ((inhibit-read-only t))
                (setq Info-current-file nil
                      Info-current-subfile nil
                      Info-current-file-completions nil
--- 913,942 ----
    (setq Info-current-node nil)
    (unwind-protect
        (let ((case-fold-search t)
+           (virtual-fun (Info-virtual-fun 'find-node
+                                          (or filename Info-current-file)
+                                          nodename))
            anchorpos)
!       (cond
!        ((functionp virtual-fun)
!         (let ((inhibit-read-only t)
!               (filename (or filename Info-current-file)))
!           (setq buffer-file-name nil)
!           (erase-buffer)
!           (setq Info-current-file filename)
!           (Info-virtual-call virtual-fun filename nodename no-going-back)
!           (set-buffer-modified-p nil)
!           (set-marker Info-tag-table-marker nil)
!           (set (make-local-variable 'Info-current-node-virtual) t)))
!        ((not (and
!               ;; Reread a file when moving from a virtual node.
!               (not Info-current-node-virtual)
                (or (null filename)
!                   (equal Info-current-file filename))))
!         ;; Switch files if necessary
          (let ((inhibit-read-only t))
+           (if (and Info-current-node-virtual (null filename))
+               (setq filename Info-current-file))
            (setq Info-current-file nil
                  Info-current-subfile nil
                  Info-current-file-completions nil
***************
*** 875,886 ****
              (cond
               ((eq filename t)
                (Info-insert-dir))
-              ((eq filename 'apropos)
-               (insert-buffer-substring " *info-apropos*"))
-              ((eq filename 'history)
-               (insert-buffer-substring " *info-history*"))
-              ((eq filename 'toc)
-               (insert-buffer-substring " *info-toc*"))
               (t
                  (info-insert-file-contents filename nil)
                  (setq default-directory (file-name-directory filename))))
--- 945,950 ----
***************
*** 923,929 ****
                    (cond
                     ((eq filename t) "dir")
                     (t filename)))
!             ))
          ;; Use string-equal, not equal, to ignore text props.
          (if (string-equal nodename "*")
              (progn (setq Info-current-node nodename)
--- 987,994 ----
                  (cond
                   ((eq filename t) "dir")
                   (t filename)))
!           )))
! 
          ;; Use string-equal, not equal, to ignore text props.
          (if (string-equal nodename "*")
              (progn (setq Info-current-node nodename)
***************
*** 2005,2076 ****
    (interactive)
    (Info-find-node "dir" "top"))
  
! (defun Info-history ()
!   "Go to a node with a menu of visited nodes."
!   (interactive)
!   (let ((curr-file Info-current-file)
!         (curr-node Info-current-node)
!         p)
!     (with-current-buffer (get-buffer-create " *info-history*")
!       (let ((inhibit-read-only t))
!         (erase-buffer)
!         (goto-char (point-min))
!         (insert "\n\^_\nFile: history,  Node: Top,  Up: (dir)\n\n")
!         (insert "Recently Visited Nodes\n**********************\n\n")
          (insert "* Menu:\n\n")
!         (let ((hl (delete '("history" "Top") Info-history-list)))
            (while hl
              (let ((file (nth 0 (car hl)))
                    (node (nth 1 (car hl))))
-               (if (and (equal file curr-file)
-                        (equal node curr-node))
-                   (setq p (point)))
                (if (stringp file)
                  (insert "* " node ": ("
                          (propertize (or (file-name-directory file) "") 
'invisible t)
                          (file-name-nondirectory file)
                          ")" node ".\n")))
!             (setq hl (cdr hl))))))
!     (Info-find-node 'history "Top")
!     (goto-char (or p (point-min)))))
  
! (defun Info-toc ()
!   "Go to a node with table of contents of the current Info file.
! Table of contents is created from the tree structure of menus."
    (interactive)
!   (if (stringp Info-current-file)
!       (let ((curr-file (substring-no-properties Info-current-file))
!           (curr-node (substring-no-properties Info-current-node))
!           p)
!       (with-current-buffer (get-buffer-create " *info-toc*")
!         (let ((inhibit-read-only t)
                (node-list (Info-toc-nodes curr-file)))
!           (erase-buffer)
!           (goto-char (point-min))
!           (insert "\n\^_\nFile: toc,  Node: Top,  Up: (dir)\n\n")
!           (insert "Table of Contents\n*****************\n\n")
!           (insert "*Note Top: (" curr-file ")Top.\n")
!           (Info-insert-toc
             (nth 3 (assoc "Top" node-list)) ; get Top nodes
!            node-list 0 curr-file))
!         (if (not (bobp))
              (let ((Info-hide-note-references 'hide)
                    (Info-fontify-visited-nodes nil))
!               (Info-mode)
!               (setq Info-current-file 'toc Info-current-node "Top")
                (goto-char (point-min))
                (narrow-to-region (or (re-search-forward "\n[\^_\f]\n" nil t)
                                      (point-min))
                                  (point-max))
                (Info-fontify-node)
!               (widen)))
          (goto-char (point-min))
!         (if (setq p (search-forward (concat "*Note " curr-node ":") nil t))
!             (setq p (- p (length curr-node) 2))))
!       (Info-find-node 'toc "Top")
!       (goto-char (or p (point-min))))))
  
! (defun Info-insert-toc (nodes node-list level curr-file)
    "Insert table of contents with references to nodes."
    (let ((section "Top"))
      (while nodes
--- 2070,2157 ----
    (interactive)
    (Info-find-node "dir" "top"))
  
! (add-to-list 'Info-virtual-files
!            '("^\\*History\\*$"
!              (toc-nodes . Info-history-toc-nodes)
!              (find-file . Info-history-find-file)
!              (find-node . Info-history-find-node)
!              ))
! 
! (defun Info-history-toc-nodes (filename)
!   "History-specific implementation of Info-history-toc-nodes."
!   `(,filename
!     ("Top" nil nil nil)))
! 
! (defun Info-history-find-file (filename &optional noerror)
!   "History-specific implementation of Info-find-file."
!   filename)
! 
! (defun Info-history-find-node (filename nodename &optional no-going-back)
!   "History-specific implementation of Info-find-node-2."
!   (insert (format "\n\^_\nFile: %s,  Node: %s,  Up: (dir)\n\n"
!                 (or filename Info-current-file) nodename))
!   (insert "Recently Visited Nodes\n")
!   (insert "**********************\n\n")
    (insert "* Menu:\n\n")
!   (let ((hl (delete '("*History*" "Top") Info-history-list)))
      (while hl
        (let ((file (nth 0 (car hl)))
            (node (nth 1 (car hl))))
        (if (stringp file)
            (insert "* " node ": ("
                    (propertize (or (file-name-directory file) "") 'invisible t)
                    (file-name-nondirectory file)
                    ")" node ".\n")))
!       (setq hl (cdr hl)))))
  
! (defun Info-history ()
!   "Go to a node with a menu of visited nodes."
    (interactive)
!   (Info-find-node "*History*" "Top")
!   (Info-next-reference)
!   (Info-next-reference))
! 
! (add-to-list 'Info-virtual-nodes
!            '("^\\*TOC.*\\*$"
!              (find-node . Info-toc-find-node)
!              ))
! 
! (defun Info-toc-find-node (filename nodename &optional no-going-back)
!   "Toc-specific implementation of Info-find-node-2."
!   (let* ((curr-file (substring-no-properties (or filename Info-current-file)))
!        (curr-node (substring-no-properties (or nodename Info-current-node)))
         (node-list (Info-toc-nodes curr-file)))
!     (insert (format "\n\^_\nFile: %s,  Node: %s,  Up: Top\n\n"
!                   curr-file curr-node))
!     (insert "Table of Contents\n")
!     (insert "*****************\n\n")
!     (insert "*Note Top::\n")
!     (Info-toc-insert
       (nth 3 (assoc "Top" node-list))  ; get Top nodes
!      node-list 0 curr-file)
!     (unless (bobp)
        (let ((Info-hide-note-references 'hide)
            (Info-fontify-visited-nodes nil))
!       (setq Info-current-file filename Info-current-node "*TOC*")
        (goto-char (point-min))
        (narrow-to-region (or (re-search-forward "\n[\^_\f]\n" nil t)
                              (point-min))
                          (point-max))
        (Info-fontify-node)
!       (widen)))))
! 
! (defun Info-toc ()
!   "Go to a node with table of contents of the current Info file.
! Table of contents is created from the tree structure of menus."
!   (interactive)
!   (Info-find-node Info-current-file "*TOC*")
!   (let ((prev-node (nth 1 (car Info-history))) p)
      (goto-char (point-min))
!     (if (setq p (search-forward (concat "*Note " prev-node ":") nil t))
!       (setq p (- p (length prev-node) 2)))
!     (goto-char (or p (point-min)))))
  
! (defun Info-toc-insert (nodes node-list level curr-file)
    "Insert table of contents with references to nodes."
    (let ((section "Top"))
      (while nodes
***************
*** 2078,2088 ****
          (unless (member (nth 2 node) (list nil section))
            (insert (setq section (nth 2 node)) "\n"))
          (insert (make-string level ?\t))
!         (insert "*Note " (car nodes) ": (" curr-file ")" (car nodes) ".\n")
!         (Info-insert-toc (nth 3 node) node-list (1+ level) curr-file)
          (setq nodes (cdr nodes))))))
  
! (defun Info-build-toc (file)
    "Build table of contents from menus of Info FILE and its subfiles."
    (with-temp-buffer
      (let* ((file (and (stringp file) (Info-find-file file)))
--- 2159,2169 ----
          (unless (member (nth 2 node) (list nil section))
            (insert (setq section (nth 2 node)) "\n"))
          (insert (make-string level ?\t))
!         (insert "*Note " (car nodes) ":: \n")
!         (Info-toc-insert (nth 3 node) node-list (1+ level) curr-file)
          (setq nodes (cdr nodes))))))
  
! (defun Info-toc-build (file)
    "Build table of contents from menus of Info FILE and its subfiles."
    (with-temp-buffer
      (let* ((file (and (stringp file) (Info-find-file file)))
***************
*** 2162,2184 ****
  SECTION is the section name in the Top node where this node is placed,
  CHILDREN is a list of child nodes extracted from the node menu.")
  
! (defun Info-toc-nodes (file)
!   "Return a node list of Info FILE with parent-children information.
  This information is cached in the variable `Info-toc-nodes' with the help
! of the function `Info-build-toc'."
!   (or file (setq file Info-current-file))
!   (or (assoc file Info-toc-nodes)
        ;; Skip virtual Info files
!       (and (or (not (stringp file))
!              (member file '("dir" apropos history toc)))
!            (push (cons file nil) Info-toc-nodes))
        ;; Scan the entire manual and cache the result in Info-toc-nodes
!       (let ((nodes (Info-build-toc file)))
!       (push (cons file nodes) Info-toc-nodes)
        nodes)
        ;; If there is an error, still add nil to the cache
!       (push (cons file nil) Info-toc-nodes))
!   (cdr (assoc file Info-toc-nodes)))
  
  
  (defun Info-follow-reference (footnotename &optional fork)
--- 2243,2270 ----
  SECTION is the section name in the Top node where this node is placed,
  CHILDREN is a list of child nodes extracted from the node menu.")
  
! (defun Info-toc-nodes (filename)
!   "Return a node list of Info FILENAME with parent-children information.
  This information is cached in the variable `Info-toc-nodes' with the help
! of the function `Info-toc-build'."
!   (cond
!    ((Info-virtual-call
!      (Info-virtual-fun 'toc-nodes (or filename Info-current-file) nil)
!      filename))
!    (t
!     (or filename (setq filename Info-current-file))
!     (or (assoc filename Info-toc-nodes)
        ;; Skip virtual Info files
!       (and (or (not (stringp filename))
!                (member filename '("dir")))
!            (push (cons filename nil) Info-toc-nodes))
        ;; Scan the entire manual and cache the result in Info-toc-nodes
!       (let ((nodes (Info-toc-build filename)))
!         (push (cons filename nodes) Info-toc-nodes)
          nodes)
        ;; If there is an error, still add nil to the cache
!       (push (cons filename nil) Info-toc-nodes))
!     (cdr (assoc filename Info-toc-nodes)))))
  
  
  (defun Info-follow-reference (footnotename &optional fork)
***************
*** 2792,2798 ****
    (or (assoc file Info-index-nodes)
        ;; Skip virtual Info files
        (and (or (not (stringp file))
!              (member file '("dir" apropos history toc)))
             (setq Info-index-nodes (cons (cons file nil) Info-index-nodes)))
        (if (Info-file-supports-index-cookies file)
          ;; Find nodes with index cookie
--- 2878,2885 ----
    (or (assoc file Info-index-nodes)
        ;; Skip virtual Info files
        (and (or (not (stringp file))
!              (Info-virtual-file file)
!              (member file '("dir")))
             (setq Info-index-nodes (cons (cons file nil) Info-index-nodes)))
        (if (Info-file-supports-index-cookies file)
          ;; Find nodes with index cookie
***************
*** 2860,2867 ****
  If NODE is nil, check the current Info node.
  If FILE is nil, check the current Info file."
    (or file (setq file Info-current-file))
!   (if (or (and node (not (equal node Info-current-node)))
            (assoc file Info-index-nodes))
        (member (or node Info-current-node) (Info-index-nodes file))
      ;; Don't search all index nodes if request is only for the current node
      ;; and file is not in the cache of index nodes
--- 2947,2955 ----
  If NODE is nil, check the current Info node.
  If FILE is nil, check the current Info file."
    (or file (setq file Info-current-file))
!   (if (and (or (and node (not (equal node Info-current-node)))
               (assoc file Info-index-nodes))
+          (not Info-current-node-virtual))
        (member (or node Info-current-node) (Info-index-nodes file))
      ;; Don't search all index nodes if request is only for the current node
      ;; and file is not in the cache of index nodes
***************
*** 3001,3010 ****
        (progn (beginning-of-line) t)  ;; non-nil for recursive call
        (goto-char (point-min)))))
  
! ;;;###autoload
! (defun info-apropos (string)
!   "Grovel indices of all known Info files on your system for STRING.
! Build a menu of the possible matches."
    (interactive "sIndex apropos: ")
    (unless (string= string "")
      (let ((pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ 
\t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
--- 3089,3244 ----
        (progn (beginning-of-line) t)  ;; non-nil for recursive call
        (goto-char (point-min)))))
  
! (add-to-list 'Info-virtual-nodes
!            '("^\\*Index.*\\*$"
!              (find-node . Info-virtual-index-find-node)
!              ))
! 
! (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."
!   ;; `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)
!       (Info-index topic)
!       (setq Info-history-list ohist-list)
!       (Info-goto-node orignode)
!       (push (cons (cons Info-current-file topic) Info-index-alternatives)
!             Info-virtual-index-nodes)))
!     (Info-find-node Info-current-file (format "*Index for `%s'*" topic))))
! 
! (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)
!              ))
! 
! (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))."
    (interactive "sIndex apropos: ")
    (unless (string= string "")
      (let ((pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ 
\t]+\\([^\n]+\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
***************
*** 3056,3078 ****
        (setq Info-history ohist
            Info-history-list ohist-list)
        (message "Searching indices...done")
!       (if (null matches)
!         (message "No matches found")
!       (with-current-buffer (get-buffer-create " *info-apropos*")
!         (erase-buffer)
!         (insert "\n\^_\nFile: apropos, Node: Index, Up: (dir)\n")
!         (insert "* Menu: \nNodes whose indices contain `" string "':\n\n")
!         (dolist (entry (nreverse matches))
!           (insert
!            (format "* %-38s (%s)%s.%s\n"
!                    (concat (nth 1 entry) " [" (nth 0 entry) "]:")
!                    (nth 0 entry)
!                    (nth 2 entry)
!                    (if (nth 3 entry)
!                        (concat " (line " (nth 3 entry) ")")
!                      "")))))
!       (Info-find-node 'apropos "Index")
!       (setq Info-complete-cache nil)))))
  
  (defun Info-undefined ()
    "Make command be undefined in Info."
--- 3290,3313 ----
        (setq Info-history ohist
            Info-history-list ohist-list)
        (message "Searching indices...done")
!       (or (nreverse matches) t))))
! 
! ;;;###autoload
! (defun info-apropos (string)
!   "Grovel indices of all known Info files on your system for STRING.
! Build a menu of the possible matches."
!   (interactive "sIndex apropos: ")
!   (if (equal string "")
!       (Info-find-node Info-apropos-file "Top")
!     (let* ((nodes Info-apropos-nodes) nodename)
!       (while (and nodes (not (equal string (nth 1 (car nodes)))))
!       (setq nodes (cdr nodes)))
!       (if nodes
!         (Info-find-node Info-apropos-file (car (car nodes)))
!       (setq nodename (format "Index for `%s'" string))
!       (push (list nodename string (Info-apropos-matches string))
!             Info-apropos-nodes)
!       (Info-find-node Info-apropos-file nodename)))))
  
  (defun Info-undefined ()
    "Make command be undefined in Info."
***************
*** 3248,3253 ****
--- 3483,3489 ----
      (define-key map "g" 'Info-goto-node)
      (define-key map "h" 'Info-help)
      (define-key map "i" 'Info-index)
+     (define-key map "I" 'Info-virtual-index)
      (define-key map "l" 'Info-history-back)
      (define-key map "L" 'Info-history)
      (define-key map "m" 'Info-menu)
***************
*** 3830,3836 ****
                 (format "(%s)Top"
                         (if (stringp Info-current-file)
                             (file-name-nondirectory Info-current-file)
-                          ;; Can be `toc', `apropos', or even `history'.
                           Info-current-file)))))
          (insert (if (bolp) "" " > ")
                  (cond
--- 4066,4071 ----
***************
*** 4414,4420 ****
  
  (defun Info-desktop-buffer-misc-data (desktop-dirname)
    "Auxiliary information to be saved in desktop file."
!   (unless (member Info-current-file '(apropos history toc nil))
      (list Info-current-file Info-current-node)))
  
  (defun Info-restore-desktop-buffer (desktop-buffer-file-name
--- 4649,4656 ----
  
  (defun Info-desktop-buffer-misc-data (desktop-dirname)
    "Auxiliary information to be saved in desktop file."
!   (unless (or (member Info-current-file '(nil))
!             (Info-virtual-file Info-current-file))
      (list Info-current-file Info-current-node)))
  
  (defun Info-restore-desktop-buffer (desktop-buffer-file-name

-- 
Juri Linkov
http://www.jurta.org/emacs/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]