-;;; info.el --- info package for Emacs
+;; info.el --- info package for Emacs
;; Copyright (C) 1985, 1986, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
;; Free Software Foundation, Inc.
;; Maintainer: FSF
Each element of the list is a list (FILENAME NODENAME).")
(defcustom Info-enable-edit nil
- "*Non-nil means the \\<Info-mode-map>\\[Info-edit] command in Info can edit the current node.
+ "Non-nil means the \\<Info-mode-map>\\[Info-edit] command in Info can edit the current node.
This is convenient if you want to write Info files by hand.
However, we recommend that you not do this.
It is better to write a Texinfo file and generate the Info file from that,
(t :height 1.2 :inherit info-title-2))
"Face for info titles at level 1."
:group 'info)
-;; backward-compatibility alias
-(put 'Info-title-1-face 'face-alias 'info-title-1)
+(define-obsolete-face-alias 'Info-title-1-face 'info-title-1 "22.1")
(defface info-title-2
'((((type tty pc) (class color)) :foreground "lightblue" :weight bold)
(t :height 1.2 :inherit info-title-3))
"Face for info titles at level 2."
:group 'info)
-;; backward-compatibility alias
-(put 'Info-title-2-face 'face-alias 'info-title-2)
+(define-obsolete-face-alias 'Info-title-2-face 'info-title-2 "22.1")
(defface info-title-3
'((((type tty pc) (class color)) :weight bold)
(t :height 1.2 :inherit info-title-4))
"Face for info titles at level 3."
:group 'info)
-;; backward-compatibility alias
-(put 'Info-title-3-face 'face-alias 'info-title-3)
+(define-obsolete-face-alias 'Info-title-3-face 'info-title-3 "22.1")
(defface info-title-4
'((((type tty pc) (class color)) :weight bold)
(t :weight bold :inherit variable-pitch))
"Face for info titles at level 4."
:group 'info)
-;; backward-compatibility alias
-(put 'Info-title-4-face 'face-alias 'info-title-4)
+(define-obsolete-face-alias 'Info-title-4-face 'info-title-4 "22.1")
(defface info-menu-header
'((((type tty pc))
(t :underline t))
"Face for every third `*' in an Info menu."
:group 'info)
-(put 'info-menu-5 'face-alias 'info-menu-star)
+(define-obsolete-face-alias 'info-menu-5 'info-menu-star "22.1")
(defface info-xref
'((t :inherit link))
:group 'info)
(defcustom Info-fontify-visited-nodes t
- "*Non-nil to fontify references to visited nodes in `info-xref-visited' face."
+ "Non-nil to fontify references to visited nodes in `info-xref-visited' face."
:version "22.1"
:type 'boolean
:group 'info)
(defcustom Info-fontify-maximum-menu-size 100000
- "*Maximum size of menu to fontify if `font-lock-mode' is non-nil.
+ "Maximum size of menu to fontify if `font-lock-mode' is non-nil.
Set to nil to disable node fontification."
:type 'integer
:group 'info)
(defcustom Info-use-header-line t
- "*Non-nil means to put the beginning-of-node links in an Emacs header-line.
+ "Non-nil means to put the beginning-of-node links in an Emacs header-line.
A header-line does not scroll with the rest of the buffer."
:type 'boolean
:group 'info)
:group 'info)
(defcustom Info-scroll-prefer-subnodes nil
- "*If non-nil, \\<Info-mode-map>\\[Info-scroll-up] in a menu visits subnodes.
+ "If non-nil, \\<Info-mode-map>\\[Info-scroll-up] in a menu visits subnodes.
If this is non-nil, and you scroll far enough in a node that its menu
appears on the screen, the next \\<Info-mode-map>\\[Info-scroll-up]
:group 'info)
(defcustom Info-hide-note-references t
- "*If non-nil, hide the tag and section reference in *note and * menu items.
+ "If non-nil, hide the tag and section reference in *note and * menu items.
If value is non-nil but not `hide', also replaces the \"*note\" with \"see\".
If value is non-nil but not t or `hide', the reference section is still shown.
-`nil' completely disables this feature."
+`nil' completely disables this feature. If this is non-nil, you might
+want to set `Info-refill-paragraphs'."
:version "22.1"
:type '(choice (const :tag "No hiding" nil)
(const :tag "Replace tag and hide reference" t)
:group 'info)
(defcustom Info-refill-paragraphs nil
- "*If non-nil, attempt to refill paragraphs with hidden references.
+ "If non-nil, attempt to refill paragraphs with hidden references.
This refilling may accidentally remove explicit line breaks in the Info
-file, so be prepared for a few surprises if you enable this feature."
+file, so be prepared for a few surprises if you enable this feature.
+This only has an effect if `Info-hide-note-references' is non-nil."
:version "22.1"
:type 'boolean
:group 'info)
+(defcustom Info-breadcrumbs-depth 4
+ "Depth of breadcrumbs to display.
+0 means do not display breadcrumbs."
+ :type 'integer)
+
(defcustom Info-search-whitespace-regexp "\\s-+"
- "*If non-nil, regular expression to match a sequence of whitespace chars.
+ "If non-nil, regular expression to match a sequence of whitespace chars.
This applies to Info search for regular expressions.
You might want to use something like \"[ \\t\\r\\n]+\" instead.
In the Customization buffer, that is `[' followed by a space,
:group 'info)
(defcustom Info-isearch-search t
- "*If non-nil, isearch in Info searches through multiple nodes.
+ "If non-nil, isearch in Info searches through multiple nodes.
Before leaving the initial Info node, where isearch was started,
it fails once with the error message [initial node], and with
subsequent C-s/C-r continues through other nodes without failing
(defvar Info-file-supports-index-cookies nil
"Non-nil if current Info file supports index cookies.")
+(defvar Info-file-supports-index-cookies-list nil
+ "List of Info files with information about index cookies support.
+Each element of the list is a list (FILENAME SUPPORTS-INDEX-COOKIES)
+where SUPPORTS-INDEX-COOKIES can be either t or nil.")
+
(defvar Info-index-alternatives nil
"List of possible matches for last `Info-index' command.")
(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 chosen to not cause file name clashes with
+existing 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 chosen to not cause node name clashes with
+existing 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
(insert-file-contents-literally fullname visit)
(let ((inhibit-read-only t)
(coding-system-for-write 'no-conversion)
+ (inhibit-null-byte-detection t) ; Index nodes include null bytes
(default-directory (or (file-name-directory fullname)
default-directory)))
(or (consp decoder)
(setq decoder (list decoder)))
(apply 'call-process-region (point-min) (point-max)
(car decoder) t t nil (cdr decoder))))
- (insert-file-contents fullname visit))))
+ (let ((inhibit-null-byte-detection t)) ; Index nodes include null bytes
+ (insert-file-contents fullname visit)))))
+
+(defun Info-file-supports-index-cookies (&optional file)
+ "Return non-nil value if FILE supports Info index cookies.
+Info index cookies were first introduced in 4.7, and all later
+makeinfo versions output them in index nodes, so we can rely
+solely on the makeinfo version. This function caches the information
+in `Info-file-supports-index-cookies-list'."
+ (or file (setq file Info-current-file))
+ (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
+ (let ((found nil))
+ (goto-char (point-min))
+ (condition-case ()
+ (if (and (re-search-forward
+ "makeinfo[ \n]version[ \n]\\([0-9]+.[0-9]+\\)"
+ (line-beginning-position 3) t)
+ (not (version< (match-string 1) "4.7")))
+ (setq found t))
+ (error nil))
+ (setq Info-file-supports-index-cookies-list
+ (cons (cons file found) Info-file-supports-index-cookies-list)))))
+ (cdr (assoc file Info-file-supports-index-cookies-list)))
+
\f
(defun Info-default-dirs ()
(let ((source (expand-file-name "info/" source-directory))
(let (same-window-buffer-names same-window-regexps)
(info file-or-node)))
-;;;###autoload (add-hook 'same-window-regexps "\\*info\\*\\(\\|<[0-9]+>\\)")
+;;;###autoload (add-hook 'same-window-regexps (purecopy "\\*info\\*\\(\\|<[0-9]+>\\)"))
-;;;###autoload (put 'info 'info-file "emacs")
+;;;###autoload (put 'info 'info-file (purecopy "emacs"))
;;;###autoload
(defun info (&optional file-or-node buffer)
"Enter Info, the documentation browser.
The search path for Info files is in the variable `Info-directory-list'.
The top-level Info directory is made by combining all the files named `dir'
-in all the directories in that path."
+in all the directories in that path.
+
+See a list of available Info commands in `Info-mode'."
(interactive (list
(if (and current-prefix-arg (not (numberp current-prefix-arg)))
(read-file-name "Info file name: " nil nil t))
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.
- '("./")
- (if (file-name-absolute-p filename)
- ;; No point in searching for an
- ;; absolute file name
- '(nil)
- (if Info-additional-directory-list
- (append Info-directory-list
- Info-additional-directory-list)
- Info-directory-list)))))
- ;; Search the directory list for file FILENAME.
- (while (and dirs (not found))
- (setq temp (expand-file-name filename (car dirs)))
- (setq temp-downcase
- (expand-file-name (downcase filename) (car dirs)))
- ;; Try several variants of specified name.
- (let ((suffix-list Info-suffix-list)
- (lfn (if (fboundp 'msdos-long-file-names)
- (msdos-long-file-names)
- t)))
- (while (and suffix-list (not found))
- (cond ((info-file-exists-p
- (info-insert-file-contents-1
- temp (car (car suffix-list)) lfn))
- (setq found temp))
- ((info-file-exists-p
- (info-insert-file-contents-1
- temp-downcase (car (car suffix-list)) lfn))
- (setq found temp-downcase))
- ((and (fboundp 'msdos-long-file-names)
- lfn
- (info-file-exists-p
- (info-insert-file-contents-1
- 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)))
+ (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.
+ '("./")
+ (if (file-name-absolute-p filename)
+ ;; No point in searching for an
+ ;; absolute file name
+ '(nil)
+ (if Info-additional-directory-list
+ (append Info-directory-list
+ Info-additional-directory-list)
+ Info-directory-list)))))
+ ;; Search the directory list for file FILENAME.
+ (while (and dirs (not found))
+ (setq temp (expand-file-name filename (car dirs)))
+ (setq temp-downcase
+ (expand-file-name (downcase filename) (car dirs)))
+ ;; Try several variants of specified name.
+ (let ((suffix-list Info-suffix-list)
+ (lfn (if (fboundp 'msdos-long-file-names)
+ (msdos-long-file-names)
+ t)))
+ (while (and suffix-list (not found))
+ (cond ((info-file-exists-p
+ (info-insert-file-contents-1
+ temp (car (car suffix-list)) lfn))
+ (setq found temp))
+ ((info-file-exists-p
+ (info-insert-file-contents-1
+ temp-downcase (car (car suffix-list)) lfn))
+ (setq found temp-downcase))
+ ((and (fboundp 'msdos-long-file-names)
+ lfn
+ (info-file-exists-p
+ (info-insert-file-contents-1
+ 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.
(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)
- ;; 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)
-
- ;; Check makeinfo version for index cookie support
- (let ((found nil))
- (goto-char (point-min))
- (condition-case ()
- (if (and (re-search-forward
- "makeinfo[ \n]version[ \n]\\([0-9]+.[0-9]+\\)"
- (line-beginning-position 3) t)
- (not (version< (match-string 1) "4.7")))
- (setq found t))
- (error nil))
- (set (make-local-variable 'Info-file-supports-index-cookies) found))
-
- ;; See whether file has a tag table. Record the location if yes.
- (goto-char (point-max))
- (forward-line -8)
- ;; Use string-equal, not equal, to ignore text props.
- (if (not (or (string-equal nodename "*")
- (not
- (search-forward "\^_\nEnd tag table\n" nil t))))
- (let (pos)
- ;; We have a tag table. Find its beginning.
- ;; Is this an indirect file?
- (search-backward "\nTag table:\n")
- (setq pos (point))
- (if (save-excursion
- (forward-line 2)
- (looking-at "(Indirect)\n"))
- ;; It is indirect. Copy it to another buffer
- ;; and record that the tag table is in that buffer.
- (let ((buf (current-buffer))
- (tagbuf
- (or Info-tag-table-buffer
- (generate-new-buffer " *info tag table*"))))
- (setq Info-tag-table-buffer tagbuf)
- (with-current-buffer tagbuf
- (buffer-disable-undo (current-buffer))
- (setq case-fold-search t)
- (erase-buffer)
- (insert-buffer-substring buf))
- (set-marker Info-tag-table-marker
- (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)))
- ))
+ (cond
+ ((functionp virtual-fun)
+ (let ((filename (or filename Info-current-file)))
+ (setq buffer-read-only nil)
+ (setq Info-current-file filename
+ Info-current-subfile nil
+ Info-current-file-completions nil
+ buffer-file-name nil)
+ (erase-buffer)
+ (Info-virtual-call virtual-fun filename nodename no-going-back)
+ (set-marker Info-tag-table-marker nil)
+ (setq buffer-read-only t)
+ (set-buffer-modified-p 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))
+ (when Info-current-node-virtual
+ ;; When moving from a virtual node.
+ (set (make-local-variable 'Info-current-node-virtual) nil)
+ (if (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))
+
+ ;; See whether file has a tag table. Record the location if yes.
+ (goto-char (point-max))
+ (forward-line -8)
+ ;; Use string-equal, not equal, to ignore text props.
+ (if (not (or (string-equal nodename "*")
+ (not
+ (search-forward "\^_\nEnd tag table\n" nil t))))
+ (let (pos)
+ ;; We have a tag table. Find its beginning.
+ ;; Is this an indirect file?
+ (search-backward "\nTag table:\n")
+ (setq pos (point))
+ (if (save-excursion
+ (forward-line 2)
+ (looking-at "(Indirect)\n"))
+ ;; It is indirect. Copy it to another buffer
+ ;; and record that the tag table is in that buffer.
+ (let ((buf (current-buffer))
+ (tagbuf
+ (or Info-tag-table-buffer
+ (generate-new-buffer " *info tag table*"))))
+ (setq Info-tag-table-buffer tagbuf)
+ (with-current-buffer tagbuf
+ (buffer-disable-undo (current-buffer))
+ (setq case-fold-search t)
+ (erase-buffer)
+ (insert-buffer-substring buf))
+ (set-marker Info-tag-table-marker
+ (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)
(Info-select-node)
(goto-char (point-min))
+ (forward-line 1) ; skip header line
+ (when (> Info-breadcrumbs-depth 0) ; skip breadcrumbs line
+ (forward-line 1))
+
(cond (anchorpos
(let ((new-history (list Info-current-file
(substring-no-properties nodename))))
(delete new-history Info-history-list))))
(goto-char anchorpos))
((numberp Info-point-loc)
- (forward-line (1- Info-point-loc))
+ (forward-line (- Info-point-loc 2))
(setq Info-point-loc nil))
((stringp Info-point-loc)
(Info-find-index-name Info-point-loc)
(or buffers
(message "Composing main Info directory..."))
(condition-case nil
- (progn
+ ;; Index nodes include null bytes. DIR
+ ;; files should not have indices, but who
+ ;; knows...
+ (let ((inhibit-null-byte-detection t))
(insert-file-contents file)
(set (make-local-variable 'Info-dir-file-name)
file)
(delete-region (1- (point)) (point))))
;; Now remove duplicate entries under the same heading.
- (let ((seen nil)
- (limit (point-marker)))
- (goto-char start)
- (while (and (> limit (point))
- (re-search-forward "^* \\([^:\n]+:\\(:\\|[^.\n]+\\).\\)"
- limit 'move))
- ;; Fold case straight away; `member-ignore-case' here wasteful.
- (let ((x (downcase (match-string 1))))
- (if (member x seen)
- (delete-region (match-beginning 0)
- (progn (re-search-forward "^[^ \t]" nil t)
- (match-beginning 0)))
- (push x seen))))))))))
+ (let (seen)
+ (save-restriction
+ (narrow-to-region start (point))
+ (goto-char (point-min))
+ (while (re-search-forward "^* \\([^:\n]+:\\(:\\|[^.\n]+\\).\\)" nil 'move)
+ ;; Fold case straight away; `member-ignore-case' here wasteful.
+ (let ((x (downcase (match-string 1))))
+ (if (member x seen)
+ (delete-region
+ (match-beginning 0)
+ (if (re-search-forward "^[^ \t]" nil 'move)
+ (goto-char (match-beginning 0))
+ (point-max)))
+ (push x seen)))))))))))
;; Note that on entry to this function the current-buffer must be the
;; *info* buffer; not the info tags buffer.
"\\(\0[\0-\37][[][^\0]*\0[\0-\37][]]\n?\\)"
nil t)
(let* ((start (match-beginning 1)))
- (if (not (get-text-property start 'invisible))
+ (if (and (not (get-text-property start 'invisible))
+ (not (get-text-property start 'display)))
(put-text-property start (point) 'invisible t)))))
(set-buffer-modified-p nil)))
(format "Regexp search%s: "
(if case-fold-search "" " case-sensitively")))
nil 'Info-search-history)))
- (when transient-mark-mode
- (deactivate-mark))
+ (deactivate-mark)
(when (equal regexp "")
(setq regexp (car Info-search-history)))
(when regexp
(point-max)))
(while (and (not give-up)
(or (null found)
- (not (funcall isearch-success-function beg-found found))))
+ (not (funcall isearch-filter-predicate beg-found found))))
(let ((search-spaces-regexp
(if (or (not isearch-mode) isearch-regexp)
Info-search-whitespace-regexp)))
(setq give-up nil found nil)
(while (and (not give-up)
(or (null found)
- (not (funcall isearch-success-function beg-found found))))
+ (not (funcall isearch-filter-predicate beg-found found))))
(let ((search-spaces-regexp
(if (or (not isearch-mode) isearch-regexp)
Info-search-whitespace-regexp)))
(replace-regexp-in-string
"^\\W+\\|\\W+$" "" string)
nil t)
- "\\b")
+ ;; Lax version of word search
+ (if (or isearch-nonincremental
+ (eq (length string)
+ (length (isearch-string-state
+ (car isearch-cmds)))))
+ "\\b"))
bound noerror count
(unless isearch-forward 'backward))
(Info-search (if isearch-regexp string (regexp-quote string))
(progn (Info-find-node file node) (sit-for 0))))
(defun Info-isearch-start ()
- (setq Info-isearch-initial-node nil))
-
-(defun Info-search-success-function (beg-found found)
- "Skip invisible text, node header line and Tag Table node."
+ (setq Info-isearch-initial-node
+ ;; Don't stop at initial node for nonincremental search.
+ ;; Otherwise this variable is set after first search failure.
+ (and isearch-nonincremental Info-current-node)))
+
+(defun Info-isearch-filter (beg-found found)
+ "Test whether the current search hit is a visible useful text.
+Return non-nil if the text from BEG-FOUND to FOUND is visible
+and is not in the header line or a tag table."
(save-match-data
(let ((backward (< found beg-found)))
(not
(or
- (if backward
- (or (text-property-not-all found beg-found 'invisible nil)
- (text-property-not-all found beg-found 'display nil))
- (or (text-property-not-all beg-found found 'invisible nil)
- (text-property-not-all beg-found found 'display nil)))
+ (and (not (eq search-invisible t))
+ (if backward
+ (or (text-property-not-all found beg-found 'invisible nil)
+ (text-property-not-all found beg-found 'display nil))
+ (or (text-property-not-all beg-found found 'invisible nil)
+ (text-property-not-all beg-found found 'display nil))))
;; Skip node header line
(and (save-excursion (forward-line -1)
(looking-at "\^_"))
(Info-find-node filename nodename)
(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 ()
(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)
- (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)))))
+ (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)
- (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))))))
+ (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-insert-toc (nodes node-list level curr-file)
+(defun Info-toc-insert (nodes node-list level curr-file)
"Insert table of contents with references to nodes."
(let ((section "Top"))
(while nodes
(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)
+ (insert "*Note " (car nodes) ":: \n")
+ (Info-toc-insert (nth 3 node) node-list (1+ level) curr-file)
(setq nodes (cdr nodes))))))
-(defun Info-build-toc (file)
+(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)))
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.
+(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-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)))
+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)
nextnode)
(goto-char (point-min))
(search-forward "\n* Menu:")
- (if (not (memq action '(nil t)))
- (re-search-forward
- (concat "\n\\* +" (regexp-quote string) ":") nil t)
+ (cond
+ ((eq (car-safe action) 'boundaries) nil)
+ ((eq action 'lambda)
+ (re-search-forward
+ (concat "\n\\* +" (regexp-quote string) ":") nil t))
+ (t
(let ((pattern (concat "\n\\* +\\("
(regexp-quote string)
- Info-menu-entry-name-re "\\):" Info-node-spec-re))
+ Info-menu-entry-name-re "\\):"
+ Info-node-spec-re))
completions
(complete-nodes Info-complete-nodes))
;; Check the cache.
(list Info-current-file Info-current-node
Info-complete-next-re string completions
Info-complete-nodes)))
- (if action
- (all-completions string completions predicate)
- (try-completion string completions predicate))))))))
+ (complete-with-action action completions string predicate))))))))
(defun Info-menu (menu-item &optional fork)
a new Info buffer. If FORK is a string, it is the name to use for the
new buffer."
(interactive
- (let ((completions '())
- ;; If point is within a menu item, use that item as the default
+ (let (;; If point is within a menu item, use that item as the default
(default nil)
(p (point))
beg
- (last nil)
(case-fold-search t))
(save-excursion
(goto-char (point-min))
(Info-extract-menu-node-name nil (Info-index-node))))))
;; If COUNT is nil, use the last item in the menu.
-(defun Info-extract-menu-counting (count)
+(defun Info-extract-menu-counting (count &optional no-detail)
(let ((case-fold-search t))
(save-excursion
- (let ((case-fold-search t))
+ (let ((case-fold-search t)
+ (bound (when (and no-detail
+ (re-search-forward
+ "^[ \t-]*The Detailed Node Listing" nil t))
+ (match-beginning 0))))
(goto-char (point-min))
- (or (search-forward "\n* menu:" nil t)
+ (or (search-forward "\n* menu:" bound t)
(error "No menu in this node"))
(if count
- (or (search-forward "\n* " nil t count)
+ (or (search-forward "\n* " bound t count)
(error "Too few items in menu"))
- (while (search-forward "\n* " nil t)
+ (while (search-forward "\n* " bound t)
nil))
(Info-extract-menu-node-name nil (Info-index-node))))))
(Info-goto-node "Top")
(let ((Info-history nil)
(case-fold-search t))
- ;; Go to the last node in the menu of Top.
- (Info-goto-node (Info-extract-menu-counting nil))
+ ;; Go to the last node in the menu of Top. But don't delve into
+ ;; detailed node listings.
+ (Info-goto-node (Info-extract-menu-counting nil t))
;; If the last node in the menu is not last in pointer structure,
- ;; move forward until we can't go any farther.
- (while (Info-forward-node t t) nil)
+ ;; move forward (but not down- or upward - see bug#1116) until we
+ ;; can't go any farther.
+ (while (Info-forward-node t t t) nil)
;; Then keep moving down to last subnode, unless we reach an index.
(while (and (not (Info-index-node))
(save-excursion (search-forward "\n* Menu:" nil t)))
(Info-goto-node (Info-extract-menu-counting nil)))))
-(defun Info-forward-node (&optional not-down no-error)
+(defun Info-forward-node (&optional not-down not-up no-error)
"Go forward one node, considering all nodes as forming one sequence."
(interactive)
(goto-char (point-min))
((save-excursion (search-backward "next:" nil t))
(Info-next)
t)
- ((and (save-excursion (search-backward "up:" nil t))
+ ((and (not not-up)
+ (save-excursion (search-backward "up:" nil t))
;; Use string-equal, not equal, to ignore text props.
(not (string-equal (downcase (Info-extract-pointer "up"))
"top")))
(Info-up)
(let (Info-history success)
(unwind-protect
- (setq success (Info-forward-node t no-error))
+ (setq success (Info-forward-node t nil no-error))
(or success (Info-goto-node old-node))))))
(no-error nil)
(t (error "No pointer forward from this node")))))
(or (assoc file Info-index-nodes)
;; Skip virtual Info files
(and (or (not (stringp file))
- (member file '("dir" apropos history toc)))
+ (Info-virtual-file-p file))
(setq Info-index-nodes (cons (cons file nil) Info-index-nodes)))
- (if Info-file-supports-index-cookies
+ (if (Info-file-supports-index-cookies file)
;; Find nodes with index cookie
(let* ((default-directory (or (and (stringp file)
(file-name-directory
(setq file (Info-find-file file))))
default-directory))
Info-history Info-history-list Info-fontify-maximum-menu-size
- (main-file file) subfiles nodes node)
+ (main-file file) subfiles nodes)
(condition-case nil
(with-temp-buffer
(while (or main-file subfiles)
nodes)
;; Else find nodes with the word "Index" in the node name
(let ((case-fold-search t)
- Info-history Info-history-list Info-fontify-maximum-menu-size
+ Info-history Info-history-list Info-fontify-maximum-menu-size Info-point-loc
nodes node)
(condition-case nil
(with-temp-buffer
(Info-goto-node (car nodes))
(while (and (setq node (Info-extract-pointer "next" t))
(string-match "\\<Index\\>" node))
- (setq nodes (cons node nodes))
+ (push node nodes)
(Info-goto-node node))))
(error nil))
(if nodes
"Return non-nil value if NODE is an index node.
If NODE is nil, check the current Info node.
If FILE is nil, check the current Info file."
- (if (or (and node (not (equal node Info-current-node)))
- (assoc (or file Info-current-file) Info-index-nodes))
+ (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
- (if Info-file-supports-index-cookies
- (save-excursion
- (goto-char (+ (or (save-excursion
- (search-backward "\n\^_" nil t))
- (point-min)) 2))
- (search-forward "\0\b[index\0\b]"
- (or (save-excursion
- (search-forward "\n\^_" nil t))
- (point-max)) t))
- (save-match-data
+ (save-match-data
+ (if (Info-file-supports-index-cookies file)
+ (save-excursion
+ (goto-char (+ (or (save-excursion
+ (search-backward "\n\^_" nil t))
+ (point-min)) 2))
+ (search-forward "\0\b[index\0\b]"
+ (or (save-excursion
+ (search-forward "\n\^_" nil t))
+ (point-max)) t))
(string-match "\\<Index\\>" (or node Info-current-node ""))))))
(defun Info-goto-index ()
(Info-find-index-name (match-string 1 name))))
(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."
+\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.
+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)
+ ))
+
+(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]+\\))\\)?"
(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)))))
+ (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
+(add-to-list 'Info-virtual-files
+ '("\\`\\*Finder.*\\*\\'"
+ (find-file . Info-finder-find-file)
+ (find-node . Info-finder-find-node)
+ ))
+
+(defvar Info-finder-file "*Finder*"
+ "Info file name of the virtual Info keyword finder manual.")
+
+(defun Info-finder-find-file (filename &optional noerror)
+ "Finder-specific implementation of Info-find-file."
+ filename)
+
+(defvar finder-known-keywords)
+(defvar finder-package-info)
+(declare-function find-library-name "find-func" (library))
+(declare-function lm-commentary "lisp-mnt" (&optional file))
+
+(defun Info-finder-find-node (filename nodename &optional no-going-back)
+ "Finder-specific implementation of Info-find-node-2."
+ (cond
+ ((equal nodename "Top")
+ ;; Display Top menu with descriptions of the keywords
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n"
+ Info-finder-file nodename))
+ (insert "Finder Keywords\n")
+ (insert "***************\n\n")
+ (insert "* Menu:\n\n")
+ (mapc
+ (lambda (assoc)
+ (let ((keyword (car assoc)))
+ (insert (format "* %-14s %s.\n"
+ (concat (symbol-name keyword) "::")
+ (cdr assoc)))))
+ finder-known-keywords))
+ ((string-match-p "\\.el\\'" nodename)
+ ;; Display commentary section
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
+ Info-finder-file nodename))
+ (insert "Finder Commentary\n")
+ (insert "*****************\n\n")
+ (insert
+ "Commentary section of the package `" nodename "':\n\n")
+ (let ((str (lm-commentary (find-library-name nodename))))
+ (if (null str)
+ (insert "Can't find any Commentary section\n\n")
+ (insert
+ (with-temp-buffer
+ (insert str)
+ (goto-char (point-min))
+ (delete-blank-lines)
+ (goto-char (point-max))
+ (delete-blank-lines)
+ (goto-char (point-min))
+ (while (re-search-forward "^;+ ?" nil t)
+ (replace-match "" nil nil))
+ (buffer-string))))))
+ (t
+ ;; Display packages that match the keyword
+ (insert (format "\n\^_\nFile: %s, Node: %s, Up: Top\n\n"
+ Info-finder-file nodename))
+ (insert "Finder Packages\n")
+ (insert "***************\n\n")
+ (insert
+ "The following packages match the keyword `" nodename "':\n\n")
+ (insert "* Menu:\n\n")
+ (let ((id (intern nodename)))
+ (mapc
+ (lambda (x)
+ (when (memq id (cadr (cdr x)))
+ (insert (format "* %-16s %s.\n"
+ (concat (car x) "::")
+ (cadr x)))))
+ finder-package-info)))))
+;;;###autoload
+(defun info-finder ()
+ "Display descriptions of the keywords in the Finder virtual manual."
+ (interactive)
+ (require 'finder)
+ (Info-find-node Info-finder-file "Top"))
+\f
(defun Info-undefined ()
"Make command be undefined in Info."
(interactive)
At end of the node's text, moves to the next node, or up if none."
(interactive "e")
(mouse-set-point click)
- (and (not (Info-try-follow-nearest-node))
+ (and (not (Info-follow-nearest-node))
(save-excursion (forward-line 1) (eobp))
(Info-next-preorder)))
(Info-goto-node
(Info-extract-menu-item (match-string-no-properties 1)) fork)
t)))
+ (and (eq this-command 'Info-mouse-follow-nearest-node)
+ ;; Don't raise an error when mouse-1 is bound to this - it's
+ ;; often used to simply select the window or frame.
+ (eq 'mouse-1 (event-basic-type last-input-event)))
(error "Point neither on reference nor in menu item description")))
;; Common subroutine.
(defun Info-try-follow-nearest-node (&optional fork)
"Follow a node reference near point. Return non-nil if successful.
-If FORK is non-nil, it i spassed to `Info-goto-node'."
+If FORK is non-nil, it is passed to `Info-goto-node'."
(let (node)
(cond
- ((Info-get-token (point) "[hf]t?tps?://" "[hf]t?tps?://\\([^ \t\n\"`({<>})']+\\)")
- (setq node t)
- (browse-url (browse-url-url-at-point)))
+ ((setq node (Info-get-token (point) "[hf]t?tps?://"
+ "\\([hf]t?tps?://[^ \t\n\"`({<>})']+\\)"))
+ (browse-url node)
+ (setq node t))
((setq node (Info-get-token (point) "\\*note[ \n\t]+"
"\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))
(Info-follow-reference node fork))
(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)
(define-key map "r" 'Info-history-forward)
(define-key map "s" 'Info-search)
(define-key map "S" 'Info-search-case-sensitively)
- ;; For consistency with Rmail.
- (define-key map "\M-s" 'Info-search)
(define-key map "\M-n" 'clone-buffer)
(define-key map "t" 'Info-top-node)
(define-key map "T" 'Info-toc)
:help "Look for a string in the index items"]
["Next Matching Item" Info-index-next :active Info-index-alternatives
:help "Look for another occurrence of previous item"]
+ ["Lookup a string and display index of results..." Info-virtual-index
+ :help "Look for a string in the index items and display node with results"]
["Lookup a string in all indices..." info-apropos
:help "Look for a string in the indices of all manuals"])
["Copy Node Name" Info-copy-current-node-name
(defvar info-tool-bar-map
- (if (display-graphic-p)
- (let ((map (make-sparse-keymap)))
- (tool-bar-local-item-from-menu 'Info-history-back "left-arrow" map Info-mode-map
- :rtl "right-arrow")
- (tool-bar-local-item-from-menu 'Info-history-forward "right-arrow" map Info-mode-map
- :rtl "left-arrow")
- (tool-bar-local-item-from-menu 'Info-prev "prev-node" map Info-mode-map
- :rtl "next-node")
- (tool-bar-local-item-from-menu 'Info-next "next-node" map Info-mode-map
- :rtl "prev-node")
- (tool-bar-local-item-from-menu 'Info-up "up-node" map Info-mode-map)
- (tool-bar-local-item-from-menu 'Info-top-node "home" map Info-mode-map)
- (tool-bar-local-item-from-menu 'Info-goto-node "jump-to" map Info-mode-map)
- (tool-bar-local-item-from-menu 'Info-index "index" map Info-mode-map)
- (tool-bar-local-item-from-menu 'Info-search "search" map Info-mode-map)
- (tool-bar-local-item-from-menu 'Info-exit "exit" map Info-mode-map)
- map)))
+ (let ((map (make-sparse-keymap)))
+ (tool-bar-local-item-from-menu 'Info-history-back "left-arrow" map Info-mode-map
+ :rtl "right-arrow")
+ (tool-bar-local-item-from-menu 'Info-history-forward "right-arrow" map Info-mode-map
+ :rtl "left-arrow")
+ (tool-bar-local-item-from-menu 'Info-prev "prev-node" map Info-mode-map
+ :rtl "next-node")
+ (tool-bar-local-item-from-menu 'Info-next "next-node" map Info-mode-map
+ :rtl "prev-node")
+ (tool-bar-local-item-from-menu 'Info-up "up-node" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-top-node "home" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-goto-node "jump-to" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-index "index" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-search "search" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-exit "exit" map Info-mode-map)
+ map))
(defvar Info-menu-last-node nil)
;; Last node the menu was created for.
\\[Info-search] Search through this Info file for specified regexp,
and select the node in which the next occurrence is found.
\\[Info-search-case-sensitively] Search through this Info file for specified regexp case-sensitively.
-\\[Info-search-next] Search for another occurrence of regexp
- from a previous \\<Info-mode-map>\\[Info-search] command.
+\\[isearch-forward], \\[isearch-forward-regexp] Use Isearch to search through multiple Info nodes.
\\[Info-index] Search for a topic in this manual's Index and go to index entry.
\\[Info-index-next] (comma) Move to the next match from a previous \\<Info-mode-map>\\[Info-index] command.
+\\[Info-virtual-index] Look for a string and display the index node with results.
\\[info-apropos] Look for a string in the indices of all manuals.
\\[Info-goto-node] Move to node specified by name.
You may include a filename as well, as (FILENAME)NODENAME.
(make-local-variable 'Info-history)
(make-local-variable 'Info-history-forward)
(make-local-variable 'Info-index-alternatives)
- (setq header-line-format
- (if Info-use-header-line
- '(:eval (get-text-property (point-min) 'header-line))
- nil)) ; so the header line isn't displayed
+ (if Info-use-header-line ; do not override global header lines
+ (setq header-line-format
+ '(:eval (get-text-property (point-min) 'header-line))))
(set (make-local-variable 'tool-bar-map) info-tool-bar-map)
;; This is for the sake of the invisible text we use handling titles.
(make-local-variable 'line-move-ignore-invisible)
'Info-isearch-wrap)
(set (make-local-variable 'isearch-push-state-function)
'Info-isearch-push-state)
- (set (make-local-variable 'isearch-success-function)
- 'Info-search-success-function)
+ (set (make-local-variable 'isearch-filter-predicate)
+ 'Info-isearch-filter)
(set (make-local-variable 'search-whitespace-regexp)
Info-search-whitespace-regexp)
(set (make-local-variable 'revert-buffer-function)
(cdr where))
where)))
-;;;###autoload (put 'Info-goto-emacs-command-node 'info-file "emacs")
+;;;###autoload (put 'Info-goto-emacs-command-node 'info-file (purecopy "emacs"))
;;;###autoload
(defun Info-goto-emacs-command-node (command)
"Go to the Info node in the Emacs manual for command COMMAND.
(if (> num-matches 2) "them" "it")))))
(error "Couldn't find documentation for %s" command))))
-;;;###autoload (put 'Info-goto-emacs-key-command-node 'info-file "emacs")
+;;;###autoload (put 'Info-goto-emacs-key-command-node 'info-file (purecopy "emacs"))
;;;###autoload
(defun Info-goto-emacs-key-command-node (key)
"Go to the node in the Emacs manual which describes the command bound to KEY.
(let ((command (key-binding key)))
(cond ((null command)
(message "%s is undefined" (key-description key)))
- ((and (interactive-p)
+ ((and (called-interactively-p 'interactive)
(eq command 'execute-extended-command))
(Info-goto-emacs-command-node
(read-command "Find documentation for command: ")))
keymap)
"Keymap to put on the Up link in the text or the header line.")
-(defcustom Info-breadcrumbs-depth 4
- "Depth of breadcrumbs to display.
-0 means do not display breadcrumbs."
- :type 'integer)
-
(defun Info-insert-breadcrumbs ()
(let ((nodes (Info-toc-nodes Info-current-file))
(node Info-current-node)
(format "(%s)Top"
(if (stringp Info-current-file)
(file-name-nondirectory Info-current-file)
- ;; Can be `toc', `apropos', or even `history'.
+ ;; Some legacy code can still use a symbol.
Info-current-file)))))
(insert (if (bolp) "" " > ")
(cond
((string-equal (downcase tag) "prev") Info-prev-link-keymap)
((string-equal (downcase tag) "next") Info-next-link-keymap)
((string-equal (downcase tag) "up" ) Info-up-link-keymap))))))
-
+
(when (> Info-breadcrumbs-depth 0)
(Info-insert-breadcrumbs))
-
+
;; Treat header line.
(when Info-use-header-line
(goto-char (point-min))
;; This is a serious problem for trying to handle multiple
;; frame types at once. We want this text to be invisible
;; on frames that can display the font above.
- (when (memq (framep (selected-frame)) '(x pc w32 mac ns))
+ (when (memq (framep (selected-frame)) '(x pc w32 ns))
(add-text-properties (1- (match-beginning 2)) (match-end 2)
'(invisible t front-sticky nil rear-nonsticky t)))))
(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))
+ (unless (Info-virtual-file-p Info-current-file)
(list Info-current-file Info-current-node)))
(defun Info-restore-desktop-buffer (desktop-buffer-file-name
(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
(defun Info-bookmark-make-record ()
+ "This implements the `bookmark-make-record-function' type (which see)
+for Info nodes."
`(,Info-current-node
,@(bookmark-make-record-default 'point-only)
(filename . ,Info-current-file)
;;;###autoload
(defun Info-bookmark-jump (bmk)
- ;; This implements the `handler' function interface for record type returned
- ;; by `Info-bookmark-make-record', which see.
+ "This implements the `handler' function interface for the record
+type returned by `Info-bookmark-make-record', which see."
(let* ((file (bookmark-prop-get bmk 'filename))
(info-node (bookmark-prop-get bmk 'info-node))
(buf (save-window-excursion ;FIXME: doesn't work with frames!