;;; info.el --- info package for Emacs.
-;; Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 97, 98 Free Software
+;; Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 97, 98, 99 Free Software
;; Foundation, Inc.
;; Maintainer: FSF
;;; Code:
+(eval-when-compile (require 'jka-compr))
+
(defgroup info nil
"Info subsystem"
:group 'help
:type 'integer
:group 'info)
-(defvar Info-directory-list
- (let ((path (getenv "INFOPATH"))
- ;; This is for older Emacs versions
- ;; which might get this info.el from the Texinfo distribution.
- (path-separator (if (boundp 'path-separator) path-separator
- (if (eq system-type 'ms-dos) ";" ":")))
- (source (expand-file-name "info/" source-directory))
- (sibling (if installation-directory
- (expand-file-name "info/" installation-directory)))
- alternative)
- (if path
- (let ((list nil)
- idx)
- (while (> (length path) 0)
- (setq idx (or (string-match path-separator path) (length path))
- list (cons (substring path 0 idx) list)
- path (substring path (min (1+ idx)
- (length path)))))
- (nreverse list))
- (if (and sibling (file-exists-p sibling))
- (setq alternative sibling)
- (setq alternative source))
- (if (or (member alternative Info-default-directory-list)
- (not (file-exists-p alternative))
- ;; On DOS/NT, we use movable executables always,
- ;; and we must always find the Info dir at run time.
- (if (or (eq system-type 'ms-dos) (eq system-type 'windows-nt))
- nil
- ;; Use invocation-directory for Info only if we used it for
- ;; exec-directory also.
- (not (string= exec-directory
- (expand-file-name "lib-src/"
- installation-directory)))))
- Info-default-directory-list
- (reverse (cons alternative
- (cdr (reverse Info-default-directory-list)))))))
+(defvar Info-directory-list nil
"List of directories to search for Info documentation files.
nil means not yet initialized. In this case, Info uses the environment
variable INFOPATH to initialize it, or `Info-default-directory-list'
(defvar Info-current-file nil
"Info file that Info is now looking at, or nil.
This is the name that was specified in Info, not the actual file name.
-It doesn't contain directory names or file name extensions added by Info.")
+It doesn't contain directory names or file name extensions added by Info.
+Can also be t when using `Info-on-current-buffer'.")
(defvar Info-current-subfile nil
"Info subfile that is actually in the *info* buffer now,
(defvar Info-standalone nil
"Non-nil if Emacs was started solely as an Info browser.")
-
+\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.
(if (eq system-type 'ms-dos)
'( (".gz" . "gunzip")
(".z" . "gunzip")
+ (".bz2" . "bzip2 -dc")
(".inz" . "gunzip")
(".igz" . "gunzip")
(".info.Z" . "gunzip")
(".info.Y". "unyabba")
(".info.gz". "gunzip")
(".info.z". "gunzip")
+ (".info.bz2" . "bzip2 -dc")
(".info". nil)
("-info.Z". "uncompress")
("-info.Y". "unyabba")
("-info.gz". "gunzip")
+ ("-info.bz2" . "bzip2 -dc")
("-info.z". "gunzip")
("-info". nil)
("/index.Z". "uncompress")
("/index.Y". "unyabba")
("/index.gz". "gunzip")
("/index.z". "gunzip")
+ ("/index.bz2". "bzip2 -dc")
("/index". nil)
(".Z". "uncompress")
(".Y". "unyabba")
(".gz". "gunzip")
(".z". "gunzip")
+ (".bz2" . "bzip2 -dc")
("". nil)))
"List of file name suffixes and associated decoding commands.
Each entry should be (SUFFIX . STRING); the file is given to
default-directory)))
(call-process-region (point-min) (point-max) decoder t t)))
(insert-file-contents fullname visit))))
+\f
+;; Initialize Info-directory-list, if that hasn't been done yet.
+(defun info-initialize ()
+ (unless Info-directory-list
+ (let ((path (getenv "INFOPATH"))
+ (source (expand-file-name "info/" source-directory))
+ (sibling (if installation-directory
+ (expand-file-name "info/" installation-directory)))
+ alternative)
+ (setq Info-directory-list
+ (if path
+ (split-string path (regexp-quote path-separator))
+ (if (and sibling (file-exists-p sibling))
+ ;; Uninstalled, Emacs builddir != srcdir.
+ (setq alternative sibling)
+ ;; Uninstalled, builddir == srcdir
+ (setq alternative source))
+ (if (or (member alternative Info-default-directory-list)
+ ;; On DOS/NT, we use movable executables always,
+ ;; and we must always find the Info dir at run time.
+ (if (memq system-type '(ms-dos windows-nt))
+ nil
+ ;; Use invocation-directory for Info
+ ;; only if we used it for exec-directory also.
+ (not (string= exec-directory
+ (expand-file-name "lib-src/"
+ installation-directory))))
+ (not (file-exists-p alternative)))
+ Info-default-directory-list
+ ;; `alternative' contains the Info files that came with this
+ ;; version, so we should look there first. `Info-insert-dir'
+ ;; currently expects to find `alternative' first on the list.
+ (cons alternative
+ (reverse (cdr (reverse Info-default-directory-list))))))))))
;;;###autoload
(defun info-other-window (&optional file)
"Enter Info, the documentation browser.
Optional argument FILE specifies the file to examine;
the default is the top-level directory of Info.
+Called from a program, FILE may specify an Info node of the form
+`(FILENAME)NODENAME'.
In interactive use, a prefix argument directs this command
to read a file name from the minibuffer.
(interactive (if current-prefix-arg
(list (read-file-name "Info file name: " nil nil t))))
(if file
- (progn (pop-to-buffer "*info*")
- (Info-goto-node (concat "(" file ")")))
+ (progn
+ (pop-to-buffer "*info*")
+ ;; If argument already contains parentheses, don't add another set
+ ;; since the argument will then be parsed improperly. This also
+ ;; has the added benefit of allowing node names to be included
+ ;; following the parenthesized filename.
+ (if (and (stringp file) (string-match "(.*)" file))
+ (Info-goto-node file)
+ (Info-goto-node (concat "(" file ")"))))
(if (get-buffer "*info*")
(pop-to-buffer "*info*")
(Info-directory))))
(nth 1 err) err)))
(save-buffers-kill-emacs)))
(info)))
+\f
+;; See if the the accessible portion of the buffer begins with a node
+;; delimiter, and the node header line which follows matches REGEXP.
+;; Typically, this test will be followed by a loop that examines the
+;; rest of the buffer with (search-forward "\n\^_"), and it's a pity
+;; to have the overhead of this special test inside the loop.
+
+;; This function changes match-data, but supposedly the caller might
+;; want to use the results of re-search-backward.
+
+;; The return value is the value of point at the beginning of matching
+;; REGERXP, if the function succeeds, nil otherwise.
+(defun Info-node-at-bob-matching (regexp)
+ (and (bobp) ; are we at beginning of buffer?
+ (looking-at "\^_") ; does it begin with node delimiter?
+ (let (beg)
+ (forward-line 1)
+ (setq beg (point))
+ (forward-line 1) ; does the line after delimiter match REGEXP?
+ (re-search-backward regexp beg t))))
;; Go to an info node specified as separate filename and nodename.
;; no-going-back is non-nil if recovering from an error in this function;
;; it says do not attempt further (recursive) error recovery.
(defun Info-find-node (filename nodename &optional no-going-back)
+ (info-initialize)
;; Convert filename to lower case if not found as specified.
;; Expand it.
- (if filename
+ (if (stringp filename)
(let (temp temp-downcase found)
(setq filename (substitute-in-file-name filename))
(if (string= (downcase filename) "dir")
Info-history)))
;; Go into info buffer.
(or (eq major-mode 'Info-mode) (pop-to-buffer "*info*"))
+ (Info-find-node-2 filename nodename no-going-back))
+
+(defun Info-on-current-buffer (&optional nodename)
+ "Use the `Info-mode' to browse the current info buffer.
+If a prefix arg is provided, it queries for the NODENAME which
+else defaults to `Top'."
+ (interactive
+ (list (if current-prefix-arg
+ (completing-read "Node name: " (Info-build-node-completions)
+ nil t "Top")
+ "Top")))
+ (Info-mode)
+ (set (make-local-variable 'Info-current-file) t)
+ (Info-find-node-2 nil nodename))
+
+(defun Info-find-node-2 (filename nodename &optional no-going-back)
(buffer-disable-undo (current-buffer))
(or (eq major-mode 'Info-mode)
(Info-mode))
(setq Info-current-node nil)
(unwind-protect
;; Bind case-fold-search in case the user sets it to nil.
- (let ((case-fold-search t))
+ (let ((case-fold-search t)
+ anchorpos)
;; Switch files if necessary
(or (null filename)
(equal Info-current-file filename)
;; *Or* the same, but in an indirect subfile.
;; Search file for a suitable node.
- (let ((guesspos (point-min))
- (regexp
- (concat "\\(Node:\\|Ref:\\) *"
- (regexp-quote nodename)
- " *[,\t\n\177]")))
+ (let ((guesspos (point-min))
+ (regexp
+ (concat "\\(Node:\\|Ref:\\) *\\("
+ (regexp-quote nodename)
+ "\\) *[,\t\n\177]"))
+ (nodepos nil))
;; First, search a tag table, if any
(if (marker-position Info-tag-table-marker)
-
- (let (found-in-tag-table
- found-mode
- (m Info-tag-table-marker))
+ (let ((found-in-tag-table t)
+ found-anchor
+ found-mode
+ (m Info-tag-table-marker))
(save-excursion
(set-buffer (marker-buffer m))
(goto-char m)
(beginning-of-line) ; so re-search will work.
;; Search tag table
- (setq found-in-tag-table
- (re-search-forward regexp nil t))
+ (catch 'foo
+ (while (re-search-forward regexp nil t)
+ (setq found-anchor
+ (string-equal "Ref:" (match-string 1)))
+ (or nodepos (setq nodepos (point))
+ (if (string-equal (match-string 2) nodename)
+ (throw 'foo t))))
+ (if nodepos
+ (goto-char nodepos)
+ (setq found-in-tag-table nil)))
(if found-in-tag-table
- (setq guesspos (read (current-buffer))))
+ (setq guesspos (1+ (read (current-buffer)))))
(setq found-mode major-mode))
;; Indirect file among split files
(setq guesspos (Info-read-subfile guesspos)))))
;; Handle anchor
- (if (and found-in-tag-table
- (string-equal "Ref:" (match-string 1)))
- (goto-char guesspos)
+ (if found-anchor
+ (goto-char (setq anchorpos guesspos))
;; Else we may have a node, which we search for:
- (goto-char (max (point-min)
- (- (byte-to-position guesspos) 1000)))
+ (let ((guesschar
+ (or (byte-to-position guesspos)
+ (if (< (position-bytes (point-max)) guesspos)
+ (point-max)
+ (point-min)))))
+ (goto-char (max (point-min)
+ (- guesschar 1000))))
;; Now search from our advised position
;; (or from beg of buffer)
;; to find the actual node.
- (catch 'foo
- (while (search-forward "\n\^_" nil t)
- (forward-line 1)
- (let ((beg (point)))
- (forward-line 1)
- (if (re-search-backward regexp beg t)
- (progn
- (beginning-of-line)
- (throw 'foo t)))))
- (error
- "No such anchor in tag table or node in tag table or file: %s"
- nodename))))))
-
+ ;; First, check whether the node is right
+ ;; where we are, in case the buffer begins
+ ;; with a node.
+ (setq nodepos nil)
+ (or (Info-node-at-bob-matching regexp)
+ (catch 'foo
+ (while (search-forward "\n\^_" nil t)
+ (forward-line 1)
+ (let ((beg (point)))
+ (forward-line 1)
+ (if (re-search-backward regexp beg t)
+ (if (string-equal (match-string 2) nodename)
+ (progn
+ (beginning-of-line)
+ (throw 'foo t))
+ (or nodepos
+ (setq nodepos (point)))))))
+ (if nodepos
+ (progn
+ (goto-char nodepos)
+ (beginning-of-line))
+ (error
+ "No such anchor in tag table or node in tag table or file: %s"
+ nodename))))))
+ (goto-char (max (point-min) (- guesspos 1000)))
+ ;; Now search from our advised position (or from beg of buffer)
+ ;; to find the actual node.
+ ;; First, check whether the node is right where we are, in case
+ ;; the buffer begins with a node.
+ (setq nodepos nil)
+ (or (Info-node-at-bob-matching regexp)
+ (catch 'foo
+ (while (search-forward "\n\^_" nil t)
+ (forward-line 1)
+ (let ((beg (point)))
+ (forward-line 1)
+ (if (re-search-backward regexp beg t)
+ (if (string-equal (match-string 2) nodename)
+ (throw 'foo t)
+ (or nodepos
+ (setq nodepos (point)))))))
+ (if nodepos
+ (goto-char nodepos)
+ (error "No such node: %s" nodename))))))
(Info-select-node)
- (goto-char (point-min))))
+ (goto-char (or anchorpos (point-min)))))
;; If we did not finish finding the specified node,
;; go back to the previous one.
(or Info-current-node no-going-back (null Info-history)
;; constructed Info-dir-contents.
(defvar Info-dir-file-attributes nil)
+(defvar Info-dir-file-name nil)
+
;; Construct the Info directory node by merging the files named `dir'
;; from various directories. Set the *info* buffer's
;; default-directory to the first directory we actually get any text
;; since we used it.
(eval (cons 'and
(mapcar '(lambda (elt)
- (let ((curr (file-attributes (car elt))))
+ (let ((curr (file-attributes
+ ;; Handle symlinks
+ (file-truename (car elt)))))
+
;; Don't compare the access time.
(if curr (setcar (nthcdr 4 curr) 0))
(setcar (nthcdr 4 (cdr elt)) 0)
(equal (cdr elt) curr)))
Info-dir-file-attributes))))
- (insert Info-dir-contents)
+ (progn
+ (insert Info-dir-contents)
+ (goto-char (point-min)))
(let ((dirs Info-directory-list)
;; Bind this in case the user sets it to nil.
(case-fold-search t)
+ ;; This is set non-nil if we find a problem in some input files.
+ problems
buffers buffer others nodes dirs-done)
(setq Info-dir-file-attributes nil)
(condition-case nil
(progn
(insert-file-contents file)
+ (make-local-variable 'Info-dir-file-name)
+ (setq Info-dir-file-name file)
(setq buffers (cons (current-buffer) buffers)
Info-dir-file-attributes
(cons (cons file attrs)
(error "Can't find the Info directory node"))
;; Distinguish the dir file that comes with Emacs from all the
;; others. Yes, that is really what this is supposed to do.
- ;; If it doesn't work, fix it.
- (setq buffer (car buffers)
- others (cdr buffers))
+ ;; The definition of `Info-directory-list' puts it first on that
+ ;; list and so last in `buffers' at this point.
+ (setq buffer (car (last buffers))
+ others (delq buffer buffers))
;; Insert the entire original dir file as a start; note that we've
;; already saved its default directory to use as the default
;; Look at each of the other buffers one by one.
(while others
- (let ((other (car others)))
+ (let ((other (car others))
+ this-buffer-nodes)
;; In each, find all the menus.
(save-excursion
(set-buffer other)
(let (beg nodename end)
(forward-line 1)
(setq beg (point))
- (search-backward "\n\^_")
+ (or (search-backward "\n\^_" nil 'move)
+ (looking-at "\^_")
+ (signal 'search-failed (list "\n\^_")))
(search-forward "Node: ")
(setq nodename (Info-following-node-name))
(search-forward "\n\^_" nil 'move)
(beginning-of-line)
(setq end (point))
- (setq nodes (cons (list nodename other beg end) nodes))))))
+ (setq this-buffer-nodes
+ (cons (list nodename other beg end)
+ this-buffer-nodes))))
+ (if (assoc-ignore-case "top" this-buffer-nodes)
+ (setq nodes (nconc this-buffer-nodes nodes))
+ (setq problems t)
+ (message "No `top' node in %s" Info-dir-file-name))))
(setq others (cdr others)))
;; Add to the main menu a menu item for each other node.
(re-search-forward "^\\* Menu:")
(let ((nodename (car (car nodes))))
(goto-char (point-min))
;; Find the like-named node in the main buffer.
- (if (re-search-forward (concat "\n\^_.*\n.*Node: "
+ (if (re-search-forward (concat "^\^_.*\n.*Node: "
(regexp-quote nodename)
"[,\n\t]")
nil t)
(while buffers
(kill-buffer (car buffers))
(setq buffers (cdr buffers)))
- (message "Composing main Info directory...done"))
+ (goto-char (point-min))
+ (if problems
+ (message "Composing main Info directory...problems encountered, see `*Messages*'")
+ (message "Composing main Info directory...done")))
(setq Info-dir-contents (buffer-string)))
(setq default-directory Info-dir-contents-directory))
(save-excursion
(set-buffer (marker-buffer Info-tag-table-marker))
(goto-char (point-min))
- (search-forward "\n\^_")
+ (or (looking-at "\^_")
+ (search-forward "\n\^_"))
(forward-line 2)
(catch 'foo
(while (not (looking-at "\^_"))
(set-buffer-modified-p nil)
(setq Info-current-subfile lastfilename)))
(goto-char (point-min))
- (search-forward "\n\^_")
+ (if (looking-at "\^_")
+ (forward-char 1)
+ (search-forward "\n\^_"))
(if (numberp nodepos)
(+ (- nodepos lastfilepos) (point)))))
(let ((case-fold-search t))
(save-excursion
;; Find beginning of node.
- (search-backward "\n\^_")
- (forward-line 2)
+ (if (search-backward "\n\^_" nil 'move)
+ (forward-line 2)
+ (if (looking-at "\^_")
+ (forward-line 1)
+ (signal 'search-failed (list "\n\^_"))))
;; Get nodename spelled as it is in the node.
(re-search-forward "Node:[ \t]*")
(setq Info-current-node
(concat
" Info: ("
(if Info-current-file
- (file-name-nondirectory Info-current-file)
+ (file-name-nondirectory (if (stringp Info-current-file)
+ Info-current-file
+ (or buffer-file-name "")))
"")
")"
(or Info-current-node ""))))
;; Go to an info node specified with a filename-and-nodename string
;; of the sort that is found in pointers in nodes.
-(defun Info-goto-node (nodename)
- "Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME."
- (interactive (list (Info-read-node-name "Goto node: ")))
+(defun Info-goto-node (nodename &optional fork)
+ "Go to info node named NAME. Give just NODENAME or (FILENAME)NODENAME.
+If FORK is non-nil, show the node in a new info buffer.
+If FORK is a string, it is the name to use for the new buffer."
+ (interactive (list (Info-read-node-name "Goto node: ") current-prefix-arg))
+ (info-initialize)
+ (if fork
+ (set-buffer
+ (clone-buffer (concat "*info-" (if (stringp fork) fork nodename) "*") t)))
(let (filename)
(string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
nodename)
(or Info-current-file-completions
(let ((compl nil)
;; Bind this in case the user sets it to nil.
- (case-fold-search t))
+ (case-fold-search t)
+ (node-regexp "Node: *\\([^,\n]*\\) *[,\n\t]"))
(save-excursion
(save-restriction
(if (marker-buffer Info-tag-table-marker)
compl))))
(widen)
(goto-char (point-min))
+ ;; If the buffer begins with a node header, process that first.
+ (if (Info-node-at-bob-matching node-regexp)
+ (setq compl (list (buffer-substring (match-beginning 1)
+ (match-end 1)))))
+ ;; Now for the rest of the nodes.
(while (search-forward "\n\^_" nil t)
(forward-line 1)
(let ((beg (point)))
(forward-line 1)
- (if (re-search-backward "Node: *\\([^,\n]*\\) *[,\n\t]"
- beg t)
+ (if (re-search-backward node-regexp beg t)
(setq compl
(cons (list (buffer-substring (match-beginning 1)
(match-end 1)))
compl))))))))
+ (setq compl (cons '("*") compl))
(setq Info-current-file-completions compl))))
\f
(defun Info-restore-point (hl)
(if (equal regexp "")
(setq regexp Info-last-search)
(setq Info-last-search regexp))
- (let ((found ()) current
- (onode Info-current-node)
- (ofile Info-current-file)
- (opoint (point))
- (ostart (window-start))
- (osubfile Info-current-subfile))
- (save-excursion
- (save-restriction
- (widen)
- (if (null Info-current-subfile)
- (progn (re-search-forward regexp) (setq found (point)))
- (condition-case err
+ (when regexp
+ (let ((found ()) current
+ (onode Info-current-node)
+ (ofile Info-current-file)
+ (opoint (point))
+ (ostart (window-start))
+ (osubfile Info-current-subfile))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (null Info-current-subfile)
(progn (re-search-forward regexp) (setq found (point)))
- (search-failed nil)))))
- (if (not found) ;can only happen in subfile case -- else would have erred
- (unwind-protect
- (let ((list ()))
- (save-excursion
- (set-buffer (marker-buffer Info-tag-table-marker))
- (goto-char (point-min))
- (search-forward "\n\^_\nIndirect:")
- (save-restriction
- (narrow-to-region (point)
- (progn (search-forward "\n\^_")
- (1- (point))))
+ (condition-case err
+ (progn (re-search-forward regexp) (setq found (point)))
+ (search-failed nil)))))
+ (if (not found) ;can only happen in subfile case -- else would have erred
+ (unwind-protect
+ (let ((list ()))
+ (save-excursion
+ (set-buffer (marker-buffer Info-tag-table-marker))
(goto-char (point-min))
- (search-forward (concat "\n" osubfile ": "))
- (beginning-of-line)
- (while (not (eobp))
- (re-search-forward "\\(^.*\\): [0-9]+$")
- (goto-char (+ (match-end 1) 2))
- (setq list (cons (cons (read (current-buffer))
- (buffer-substring
- (match-beginning 1) (match-end 1)))
- list))
- (goto-char (1+ (match-end 0))))
- (setq list (nreverse list)
- current (car (car list))
- list (cdr list))))
- (while list
- (message "Searching subfile %s..." (cdr (car list)))
- (Info-read-subfile (car (car list)))
- (setq list (cdr list))
-;; (goto-char (point-min))
- (if (re-search-forward regexp nil t)
- (setq found (point) list ())))
- (if found
- (message "")
- (signal 'search-failed (list regexp))))
- (if (not found)
- (progn (Info-read-subfile osubfile)
- (goto-char opoint)
- (Info-select-node)
- (set-window-start (selected-window) ostart)))))
+ (search-forward "\n\^_\nIndirect:")
+ (save-restriction
+ (narrow-to-region (point)
+ (progn (search-forward "\n\^_")
+ (1- (point))))
+ (goto-char (point-min))
+ (search-forward (concat "\n" osubfile ": "))
+ (beginning-of-line)
+ (while (not (eobp))
+ (re-search-forward "\\(^.*\\): [0-9]+$")
+ (goto-char (+ (match-end 1) 2))
+ (setq list (cons (cons (read (current-buffer))
+ (buffer-substring
+ (match-beginning 1) (match-end 1)))
+ list))
+ (goto-char (1+ (match-end 0))))
+ (setq list (nreverse list)
+ current (car (car list))
+ list (cdr list))))
+ (while list
+ (message "Searching subfile %s..." (cdr (car list)))
+ (Info-read-subfile (car (car list)))
+ (setq list (cdr list))
+;;; (goto-char (point-min))
+ (if (re-search-forward regexp nil t)
+ (setq found (point) list ())))
+ (if found
+ (message "")
+ (signal 'search-failed (list regexp))))
+ (if (not found)
+ (progn (Info-read-subfile osubfile)
+ (goto-char opoint)
+ (Info-select-node)
+ (set-window-start (selected-window) ostart)))))
(widen)
(goto-char found)
(Info-select-node)
(or (and (string-equal onode Info-current-node)
(equal ofile Info-current-file))
(setq Info-history (cons (list ofile onode opoint)
- Info-history)))))
+ Info-history))))))
\f
;; Extract the value of the node-pointer named NAME.
;; If there is none, use ERRORNAME in the error message;
If SAME-FILE is non-nil, do not move to a different Info file."
(interactive)
(let ((node (Info-extract-pointer "up")))
- (and same-file
+ (and (or same-file (not (stringp Info-current-file)))
(string-match "^(" node)
(error "Up node is in another Info file"))
(Info-goto-node node))
(list (if (equal input "")
default input)))
(error "No cross-references in this node"))))
+
+ (unless footnotename
+ (error "No reference was specified"))
+
(let (target beg i (str (concat "\\*note " (regexp-quote footnotename)))
(case-fold-search t))
(while (setq i (string-match " " str i))
nil t))))))
-(defun Info-menu (menu-item)
+(defun Info-menu (menu-item &optional fork)
"Go to node for menu item named (or abbreviated) NAME.
Completion is allowed, and the menu item point is on is the default."
(interactive
(save-excursion
(goto-char p)
(end-of-line)
- (re-search-backward "\n\\* +\\([^:\t\n]*\\):" beg t)
- (setq default (format "%s" (buffer-substring
- (match-beginning 1)
- (match-end 1)))))))
+ (if (re-search-backward "\n\\* +\\([^:\t\n]*\\):" beg t)
+ (setq default (format "%s" (buffer-substring
+ (match-beginning 1)
+ (match-end 1))))))))
(let ((item nil))
(while (null item)
(setq item (let ((completion-ignore-case t)
(setq item default)
;; ask again
(setq item nil))))
- (list item))))
+ (list item current-prefix-arg))))
;; there is a problem here in that if several menu items have the same
;; name you can only go to the node of the first with this command.
- (Info-goto-node (Info-extract-menu-item menu-item)))
+ (Info-goto-node (Info-extract-menu-item menu-item) (if fork menu-item)))
(defun Info-extract-menu-item (menu-item)
(setq menu-item (regexp-quote menu-item))
(defun Info-next-menu-item ()
(interactive)
- (save-excursion
- (forward-line -1)
- (search-forward "\n* menu:" nil t)
- (or (search-forward "\n* " nil t)
- (error "No more items in menu"))
- (Info-goto-node (Info-extract-menu-node-name))))
+ (let ((node
+ (save-excursion
+ (forward-line -1)
+ (search-forward "\n* menu:" nil t)
+ (and (search-forward "\n* " nil t)
+ (Info-extract-menu-node-name)))))
+ (if node (Info-goto-node node)
+ (error "No more items in menu"))))
(defun Info-last-menu-item ()
(interactive)
(define-key Info-mode-map "s" 'Info-search)
;; For consistency with Rmail.
(define-key Info-mode-map "\M-s" 'Info-search)
+ (define-key Info-mode-map "\M-n" 'clone-buffer)
(define-key Info-mode-map "t" 'Info-top-node)
(define-key Info-mode-map "u" 'Info-up)
(define-key Info-mode-map "," 'Info-index-next)
;; This is for the sake of the invisible text we use handling titles.
(make-local-variable 'line-move-ignore-invisible)
(setq line-move-ignore-invisible t)
+ (add-hook (make-local-hook 'clone-buffer-hook) 'Info-clone-buffer-hook nil t)
(Info-set-mode-line)
(run-hooks 'Info-mode-hook))
+(defun Info-clone-buffer-hook ()
+ (when (bufferp Info-tag-table-buffer)
+ (setq Info-tag-table-buffer
+ (with-current-buffer Info-tag-table-buffer (clone-buffer)))
+ (let ((m Info-tag-table-marker))
+ (when (and (markerp m) (marker-position m))
+ (setq Info-tag-table-marker
+ (with-current-buffer Info-tag-table-buffer
+ (copy-marker (marker-position m))))))))
+
(defvar Info-edit-map nil
"Local keymap used within `e' command of Info.")
(if Info-edit-map
(message "Tags may have changed. Use Info-tagify if necessary")))
\f
(defvar Info-file-list-for-emacs
- '("ediff" "forms" "gnus" "info" ("mh" . "mh-e") "sc")
+ '("ediff" "forms" "gnus" "info" ("mh" . "mh-e") "sc" "message"
+ ("dired" . "dired-x") ("c" . "ccmode") "viper")
"List of Info files that describe Emacs commands.
An element can be a file name, or a list of the form (PREFIX . FILE)
where PREFIX is a name prefix and FILE is the file to look in.