As my pet project, I'm contemplating to connect Sphinx search tools with Info pages. In order to index these pages with Sphinx, I'd need them to be in plain text format and divided into nodes (i.e. I'd like to index every node separately). After some reading, I can't find a simple way of getting a list of all nodes, did I miss anything?

Actually, what I want is like (Info-directory), except I only need the list of the nodes, not the whole buffer with decoration and sectioning.

Actually, this is what I ended up doing:

(defun sphinx-info-nodes ()
  (let ((tmp-file (make-temp-file "info")))
    (shell-command (format "info --subnodes -o '%s'" tmp-file))
      (insert-file-contents tmp-file)
      (cl-loop while (re-search-forward "^\\*\\s-*\\([^:]+\\):" nil t)
               collect (match-string 1)))))

1 Answer 1

  1. If you want just a list of nodes, you can use something like Info-build-node-completions in standard library info.el:
    (defun Info-build-node-completions (&optional filename)
      (if filename
          (or (cdr (assoc filename Info-file-completions))
          (with-temp-buffer (Info-mode)
            (Info-goto-node (format "(%s)Top" filename))
            (push (cons filename Info-current-file-completions) Info-file-completions)
        (or Info-current-file-completions
  1. If you want the actual text of all of the nodes, then see library Info+ (info+.el), function (command) Info-merge-subnodes. It gives you a fundamental-mode buffer with all of the subnodes of a given node merged. You can use it on a whole manual, for instance, to get a manual-in-a-buffer. Doc string:

Info-merge-subnodes is an interactive compiled Lisp function in `info+.el'.

(Info-merge-subnodes &optional RECURSIVE-DISPLAY-P RECURSIVE-CALL-P)

For more information check the manuals.

Integrate current node with nodes referred to in its Menu.

Displays the current Info node, together with the nodes in its Menu. Buffer *Info: NODE* is used for the display, where NODE is the name of the current node. The contents of this node's subnodes (the nodes named in this node's Menu) are included in the buffer, following the contents of the current node.

Optional arg RECURSIVE-DISPLAY-P (prefix arg if interactive) governs the way menus of subnodes are treated:

  • If nil, nothing additional happens. Subnode menus are not explored. Only the current node and its immediate subnodes are documented, in the single display buffer *Info: NODE*.

  • If non-nil, then the subnodes of a node are treated in the same way as the parent node, recursively: If any of them has, itself, a Menu, then that menu's subnodes are also explored, and so on.

    • If RECURSIVE-DISPLAY-P is zero, then a single display buffer is used for all of the nodes explored. Otherwise, a separate display buffer is used for each subnode that has a Menu (see next).

      Use this when you want a single, flat compilation of the current node and all of its subnodes. It is less appropriate when the current node has several levels of subnodes: The flattened result can be difficult to read.

    • If RECURSIVE-DISPLAY-P is positive, then the contents of each subnode are displayed twice: once in the parent node's display, and once in the subnode's own display.

      Use this when the current node has several levels of subnodes and you want each display buffer to be self-contained.

    • If RECURSIVE-DISPLAY-P is negative, then there is no redundancy: A subnode's contents are only displayed in its parent's buffer. The subnode's own display buffer only contains the contents of its own subnodes.

      Use this when the current node has several levels of subnodes and you want no redundancy between the display buffers.

The user option (variable) Info-subtree-separator is a string to be inserted by Info-merge-subnodes just before the title of each node (preceding its description). By default it is "\n* ", producing a node title resembling a menu item. Setting this to "\f\n* " will cause a page break before each node description. For more on setting this variable, type C-h v Info-subtree-separator.

Optional second arg RECURSIVE-CALL-P is only for internal use. It is used to indicate whether (non-nil) or not (nil) this is a recursive (i.e. not a top-level) call to Info-merge-subnodes. Non-nil means that this is a subnode, and that its contents should only be included in the present display if RECURSIVE-DISPLAY-P is also non-nil. For proper operation when RECURSIVE-DISPLAY-P is zero, the non-nil value of RECURSIVE-CALL-P should be the node name of the top-level call to Info-merge-subnodes.

  • I'm yet not sure why, but Info-build-node-completions errors with no tags found message, but my understanding of this function is that it will only fetch the tags in one file (but I want all tags of all info files available to the system).
    – wvxvw
    Jun 29, 2015 at 17:37
  • I guess you would have to repeat it for each Info file, in that case. Dunno why it doesn't find any nodes for you. I assume that you called it from an Info buffer - if not, try that.
    – Drew
    Jun 29, 2015 at 17:58
  • (with-temp-buffer (Info-mode) (Info-build-node-completions)) gives (("*")), I'm guessing it might need some more conditions. But I also found I can do info --subnodes -o ./info.txt to achieve the effect similar to Info-directory. Though I'd still need to parse the contents of the produced file, since those aren't just nodes, but the entire info page listing the nodes.
    – wvxvw
    Jun 29, 2015 at 18:22
  • Just as a test, have you tried just C-h r and then M-: (Info-build-node-completions)? If that works then you can try to use that function as a building block. If not, I think there might be some other problem - that works for me, at least.
    – Drew
    Jun 29, 2015 at 19:00
  • Ha, now it produces extra nodes... :) I don't quite follow the logic of what the result contains. For instance, it produces a node Distrib-Footnote-1, which is not an actual Info node.
    – wvxvw
    Jun 29, 2015 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.