From: Juri Linkov <juri@jurta.org>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: emacs-devel@gnu.org
Subject: Re: Virtual Info files and nodes
Date: Tue, 30 Jun 2009 02:55:19 +0300 [thread overview]
Message-ID: <87zlbq389k.fsf@mail.jurta.org> (raw)
In-Reply-To: <jwvhbxz4esu.fsf-monnier+emacs@gnu.org> (Stefan Monnier's message of "Mon, 29 Jun 2009 10:42:28 +0200")
>>> - Why check (stringp filename) in Info-virtual-file? Isn't it an
>>> error to call it with something else than a string.
>>
>> Really only nil can be expected now,
>
> Can it? In which circumstance?
`filename' can be nil when `Info-virtual-fun' is called with non-nil
`nodename' to check for a node name when a file name is irrelevant -
its argument value is nil in this case.
>> but `stringp' is a precaution
>> against t (the current internal value for "dir" ) and former symbol
>> values `apropos', `toc' (maybe some external packages still use them).
>
> Please mention it in a comment.
Ok.
>> Info-virtual-fun expects an argument `op' for an operation type,
>> but these places call (Info-virtual-file file) with only a file name
>> argument to check whether a file name is virtual (if its name is defined
>> in a list of definitions of virtual Info files).
>
> Why not provide a dummy `find-file' value for the `op'?
> And wrap this in an Info-virtual-file-p function?
This is done in the next version below with other fixes including the
handling of "dir":
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 29 Jun 2009 23:50:55 -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-p (filename)
+ "Check if Info file FILENAME is virtual."
+ (Info-virtual-fun 'find-file filename nil))
+
+ (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 (and (stringp filename) ; some legacy code can still use a symbol
+ (cdr-safe (assoc op (assoc-default filename
+ Info-virtual-files
+ 'string-match))))
+ (and (stringp nodename) ; some legacy code can still use a symbol
+ (cdr-safe (assoc op (assoc-default nodename
+ Info-virtual-nodes
+ 'string-match))))))
+
+ (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)))
+
+ \f
(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,534 ----
(or (assoc file Info-file-supports-index-cookies-list)
;; Skip virtual Info files
(and (or (not (stringp file))
! (Info-virtual-file-p file))
(setq Info-file-supports-index-cookies-list
(cons (cons file nil) Info-file-supports-index-cookies-list)))
(save-excursion
***************
*** 660,672 ****
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
- ((string= (downcase filename) "dir")
- (setq found t))
- (t
(let ((dirs (if (string-match "^\\./" filename)
;; If specified name starts with `./'
;; then just try current directory.
--- 707,719 ----
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))
(let ((dirs (if (string-match "^\\./" filename)
;; If specified name starts with `./'
;; then just try current directory.
***************
*** 705,718 ****
temp (car (car suffix-list)) nil)))
(setq found temp)))
(setq suffix-list (cdr suffix-list))))
! (setq dirs (cdr dirs))))))
(if found
(setq filename found)
(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.
--- 752,764 ----
temp (car (car suffix-list)) nil)))
(setq found temp)))
(setq suffix-list (cdr suffix-list))))
! (setq dirs (cdr dirs))))
(if found
(setq filename found)
(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,889 ****
(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
buffer-file-name nil)
(erase-buffer)
- (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))))
(set-buffer-modified-p nil)
(set (make-local-variable 'Info-file-supports-index-cookies)
(Info-file-supports-index-cookies filename))
--- 908,944 ----
(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
buffer-file-name nil)
(erase-buffer)
(info-insert-file-contents filename nil)
! (setq default-directory (file-name-directory filename))
(set-buffer-modified-p nil)
(set (make-local-variable 'Info-file-supports-index-cookies)
(Info-file-supports-index-cookies filename))
***************
*** 919,929 ****
(match-end 0) tagbuf))
(set-marker Info-tag-table-marker pos)))
(set-marker Info-tag-table-marker nil))
! (setq Info-current-file
! (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)
--- 974,982 ----
(match-end 0) tagbuf))
(set-marker Info-tag-table-marker pos)))
(set-marker Info-tag-table-marker nil))
! (setq Info-current-file filename)
! )))
!
;; Use string-equal, not equal, to ignore text props.
(if (string-equal nodename "*")
(progn (setq Info-current-node nodename)
***************
*** 1999,2076 ****
(setq Info-history-forward history-forward)
(goto-char opoint)))
;;;###autoload
(defun Info-directory ()
"Go to the Info directory node."
(interactive)
(Info-find-node "dir" "top"))
\f
! (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
--- 2052,2165 ----
(setq Info-history-forward history-forward)
(goto-char opoint)))
\f
+ (add-to-list 'Info-virtual-files
+ '("\\`dir\\'"
+ (toc-nodes . Info-directory-toc-nodes)
+ (find-file . Info-directory-find-file)
+ (find-node . Info-directory-find-node)
+ ))
+
+ (defun Info-directory-toc-nodes (filename)
+ "Directory-specific implementation of Info-directory-toc-nodes."
+ `(,filename
+ ("Top" nil nil nil)))
+
+ (defun Info-directory-find-file (filename &optional noerror)
+ "Directory-specific implementation of Info-find-file."
+ filename)
+
+ (defun Info-directory-find-node (filename nodename &optional no-going-back)
+ "Directory-specific implementation of Info-find-node-2."
+ (Info-insert-dir))
+
;;;###autoload
(defun Info-directory ()
"Go to the Info directory node."
(interactive)
(Info-find-node "dir" "top"))
\f
! (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))
! \f
! (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)))
--- 2167,2177 ----
(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)))
\f
(defun Info-follow-reference (footnotename &optional fork)
--- 2251,2278 ----
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))
! (Info-virtual-file-p filename))
! (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)))))
\f
(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
--- 2886,2892 ----
(or (assoc file Info-index-nodes)
;; Skip virtual Info files
(and (or (not (stringp file))
! (Info-virtual-file-p file))
(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
--- 2954,2962 ----
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]+\\))\\)?"
--- 3096,3251 ----
(progn (beginning-of-line) t) ;; non-nil for recursive call
(goto-char (point-min)))))
\f
! (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))))
! \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)
! ))
!
! (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."
--- 3297,3320 ----
(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)))))
\f
(defun Info-undefined ()
"Make command be undefined in Info."
***************
*** 3248,3253 ****
--- 3490,3496 ----
(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
--- 4073,4078 ----
***************
*** 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
--- 4656,4663 ----
(defun Info-desktop-buffer-misc-data (desktop-dirname)
"Auxiliary information to be saved in desktop file."
! (unless (or (null Info-current-file)
! (Info-virtual-file-p 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/
next prev parent reply other threads:[~2009-06-29 23:55 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-28 21:28 Virtual Info files and nodes Juri Linkov
2009-06-29 0:14 ` Stefan Monnier
2009-06-29 0:48 ` Juri Linkov
2009-06-29 8:42 ` Stefan Monnier
2009-06-29 23:55 ` Juri Linkov [this message]
[not found] ` <jwvr5x11odl.fsf-monnier+emacs@gnu.org>
2009-07-01 0:01 ` Juri Linkov
2009-07-01 15:02 ` Stefan Monnier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87zlbq389k.fsf@mail.jurta.org \
--to=juri@jurta.org \
--cc=emacs-devel@gnu.org \
--cc=monnier@iro.umontreal.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.