]> code.delx.au - gnu-emacs/blobdiff - lisp/info.el
Add 2008 to copyright years.
[gnu-emacs] / lisp / info.el
index fa1e3060c1044d0d598264749aa7f2589869146d..66ca4b61000010a53ebc3245ad07ce669252d79c 100644 (file)
@@ -1,7 +1,7 @@
 ;;; 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 Free Software Foundation, Inc.
+;;   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: help
@@ -10,7 +10,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -134,7 +134,7 @@ The Lisp code is executed when the node is selected.")
   :group 'info)
 
 (defface info-xref-visited
-  '((t :inherit link-visited))
+  '((t :inherit (link-visited info-xref)))
   "Face for visited Info cross-references."
   :version "22.1"
   :group 'info)
@@ -146,7 +146,8 @@ The Lisp code is executed when the node is selected.")
   :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)
 
@@ -287,7 +288,7 @@ It doesn't contain directory names or file name extensions added by Info.")
 
 (defvar Info-current-subfile nil
   "Info subfile that is actually in the *info* buffer now.
-nil if current Info file is not split into subfiles.")
+It is nil if current Info file is not split into subfiles.")
 
 (defvar Info-current-node nil
   "Name of node that Info is now looking at, or nil.")
@@ -463,12 +464,12 @@ Do the right thing if the file has been compressed or zipped."
                     (expand-file-name "info/" installation-directory)
                   (if invocation-directory
                       (let ((infodir (expand-file-name
-                                      "../info/"
+                                      "../share/info/"
                                       invocation-directory)))
                         (if (file-exists-p infodir)
                             infodir
                           (setq infodir (expand-file-name
-                                         "../../../info/"
+                                         "../../../share/info/"
                                          invocation-directory))
                           (and (file-exists-p infodir)
                                infodir))))))
@@ -622,12 +623,6 @@ just return nil (no error)."
        (cond
         ((string= (downcase filename) "dir")
          (setq found t))
-        ((string= filename "apropos")
-         (setq found 'apropos))
-        ((string= filename "history")
-         (setq found 'history))
-        ((string= filename "toc")
-         (setq found 'toc))
         (t
          (let ((dirs (if (string-match "^\\./" filename)
                           ;; If specified name starts with `./'
@@ -673,7 +668,8 @@ just return nil (no error)."
           (if noerror
               (setq filename nil)
             (error "Info file %s does not exist" filename)))
-        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.
@@ -849,7 +845,7 @@ a case-insensitive match is tried."
                (goto-char (point-min))
                (condition-case ()
                    (if (and (re-search-forward
-                             "makeinfo version \\([0-9]+.[0-9]+\\)"
+                             "makeinfo[ \n]version[ \n]\\([0-9]+.[0-9]+\\)"
                              (line-beginning-position 3) t)
                             (not (version< (match-string 1) "4.7")))
                        (setq found t))
@@ -891,9 +887,6 @@ a case-insensitive match is tried."
               (setq Info-current-file
                    (cond
                     ((eq filename t) "dir")
-                    ((eq filename 'apropos) "apropos")
-                    ((eq filename 'history) "history")
-                    ((eq filename 'toc) "toc")
                     (t filename)))
              ))
         ;; Use string-equal, not equal, to ignore text props.
@@ -1204,7 +1197,9 @@ a case-insensitive match is tried."
                  (point)
                  (if (re-search-forward "^[^* \n\t]" nil t)
                      (match-beginning 0)
-                   (or limit (point-max)))) entries))))
+                   (or limit (point-max))))
+                entries)
+               (forward-line 0))))
          ;; Insert the entries just found.
          (while (= (line-beginning-position 0) (1- (point)))
            (backward-char))
@@ -1215,10 +1210,11 @@ a case-insensitive match is tried."
 
          ;; Now remove duplicate entries under the same heading.
          (let ((seen nil)
-               (limit (point)))
+               (limit (point-marker)))
            (goto-char start)
-           (while (re-search-forward "^* \\([^:\n]+:\\(:\\|[^.\n]+\\).\\)"
-                                     limit 'move)
+           (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)
@@ -1319,16 +1315,25 @@ any double quotes or backslashes must be escaped (\\\",\\\\)."
              nil t)
        (let* ((start (match-beginning 1))
               (parameter-alist (Info-split-parameter-string (match-string 2)))
-              (src (cdr (assoc-string "src" parameter-alist)))
-              (image-file (if src (if (file-name-absolute-p src) src
-                                    (concat default-directory src))
-                            ""))
-              (image (if (file-exists-p image-file)
-                         (create-image image-file)
-                       "[broken image]")))
-         (if (not (get-text-property start 'display))
-             (add-text-properties
-              start (point) `(display ,image rear-nonsticky (display)))))))
+               (src (cdr (assoc-string "src" parameter-alist))))
+          (if (display-images-p)
+              (let* ((image-file (if src (if (file-name-absolute-p src) src
+                                           (concat default-directory src))
+                                   ""))
+                     (image (if (file-exists-p image-file)
+                                (create-image image-file)
+                              "[broken image]")))
+                (if (not (get-text-property start 'display))
+                    (add-text-properties
+                     start (point) `(display ,image rear-nonsticky (display)))))
+            ;; text-only display, show alternative text if provided, or
+            ;; otherwise a clue that there's meant to be a picture
+            (delete-region start (point))
+            (insert (or (cdr (assoc-string "text" parameter-alist))
+                        (cdr (assoc-string "alt" parameter-alist))
+                        (and src
+                             (concat "[image:" src "]"))
+                        "[image]"))))))
     (set-buffer-modified-p nil)))
 
 ;; Texinfo 4.7 adds cookies of the form ^@^H[NAME CONTENTS ^@^H].
@@ -1395,8 +1400,8 @@ any double quotes or backslashes must be escaped (\\\",\\\\)."
 
 (defvar Info-mode-line-node-keymap
   (let ((map (make-sparse-keymap)))
-    (define-key map [mode-line mouse-1] 'Info-scroll-up)
-    (define-key map [mode-line mouse-3] 'Info-scroll-down)
+    (define-key map [mode-line mouse-1] 'Info-mouse-scroll-up)
+    (define-key map [mode-line mouse-3] 'Info-mouse-scroll-down)
     map)
   "Keymap to put on the Info node name in the mode line.")
 
@@ -1407,11 +1412,13 @@ any double quotes or backslashes must be escaped (\\\",\\\\)."
                (concat
                 " ("
                 (if (stringp Info-current-file)
-                    (file-name-nondirectory Info-current-file)
-                  "")
+                    (replace-regexp-in-string
+                     "%" "%%" (file-name-nondirectory Info-current-file))
+                  (format "*%S*" Info-current-file))
                 ") "
                 (if Info-current-node
-                    (propertize Info-current-node
+                    (propertize (replace-regexp-in-string
+                                 "%" "%%" Info-current-node)
                                 'face 'mode-line-buffer-id
                                 'help-echo
                                 "mouse-1: scroll forward, mouse-3: scroll back"
@@ -1554,6 +1561,8 @@ PATH-AND-SUFFIXES is a pair of lists, (DIRECTORIES . SUFFIXES)."
            (node-regexp "Node: *\\([^,\n]*\\) *[,\n\t]"))
        (save-excursion
          (save-restriction
+           (or Info-tag-table-marker
+               (error "No Info tags found"))
            (if (marker-buffer Info-tag-table-marker)
                (let ((marker Info-tag-table-marker))
                  (set-buffer (marker-buffer marker))
@@ -1646,8 +1655,11 @@ If DIRECTION is `backward', search in the reverse direction."
                            ;; Skip Tag Table node
                            (save-excursion
                              (and (search-backward "\^_" nil t)
-                                  (looking-at "\^_\nTag Table"))))))
-           (let ((search-spaces-regexp Info-search-whitespace-regexp))
+                                  (looking-at
+                                   "\^_\n\\(Tag Table\\|Local Variables\\)"))))))
+           (let ((search-spaces-regexp
+                  (if (or (not isearch-mode) isearch-regexp)
+                      Info-search-whitespace-regexp)))
              (if (if backward
                      (re-search-backward regexp bound t)
                    (re-search-forward regexp bound t))
@@ -1665,7 +1677,9 @@ If DIRECTION is `backward', search in the reverse direction."
       ;; If no subfiles, give error now.
       (if give-up
          (if (null Info-current-subfile)
-             (let ((search-spaces-regexp Info-search-whitespace-regexp))
+             (let ((search-spaces-regexp
+                    (if (or (not isearch-mode) isearch-regexp)
+                        Info-search-whitespace-regexp)))
                (if backward
                    (re-search-backward regexp)
                  (re-search-forward regexp)))
@@ -1734,8 +1748,11 @@ If DIRECTION is `backward', search in the reverse direction."
                                  ;; Skip Tag Table node
                                  (save-excursion
                                    (and (search-backward "\^_" nil t)
-                                        (looking-at "\^_\nTag Table"))))))
-                 (let ((search-spaces-regexp Info-search-whitespace-regexp))
+                                        (looking-at
+                                         "\^_\n\\(Tag Table\\|Local Variables\\)"))))))
+                 (let ((search-spaces-regexp
+                        (if (or (not isearch-mode) isearch-regexp)
+                            Info-search-whitespace-regexp)))
                    (if (if backward
                            (re-search-backward regexp nil t)
                          (re-search-forward regexp nil t))
@@ -1829,11 +1846,11 @@ If DIRECTION is `backward', search in the reverse direction."
 
 (defun Info-isearch-push-state ()
   `(lambda (cmd)
-     (Info-isearch-pop-state cmd ,Info-current-file ,Info-current-node)))
+     (Info-isearch-pop-state cmd ',Info-current-file ',Info-current-node)))
 
 (defun Info-isearch-pop-state (cmd file node)
-  (or (and (string= Info-current-file file)
-           (string= Info-current-node node))
+  (or (and (equal Info-current-file file)
+           (equal Info-current-node node))
       (progn (Info-find-node file node) (sit-for 0))))
 
 (defun Info-isearch-start ()
@@ -1851,7 +1868,7 @@ if ERRORNAME is nil, just return nil."
        (forward-line 1)
        (cond ((re-search-backward
                (concat name ":" (Info-following-node-name-re)) bound t)
-              (match-string 1))
+              (match-string-no-properties 1))
              ((not (eq errorname t))
               (error "Node has no %s"
                      (capitalize (or errorname name)))))))))
@@ -1873,7 +1890,7 @@ End of submatch 0, 1, and 3 are the same, so you can safely concat."
 ;;; For compatibility; other files have used this name.
 (defun Info-following-node-name ()
   (and (looking-at (Info-following-node-name-re))
-       (match-string 1)))
+       (match-string-no-properties 1)))
 
 (defun Info-next ()
   "Go to the next node of this node."
@@ -1907,7 +1924,8 @@ If SAME-FILE is non-nil, do not move to a different Info file."
       (Info-goto-node node)
       (setq p (point))
       (goto-char (point-min))
-      (if (and (search-forward "\n* Menu:" nil t)
+      (if (and (stringp old-file)
+              (search-forward "\n* Menu:" nil t)
               (re-search-forward
                (if (string-equal old-node "Top")
                    (concat "\n\\*[^:]+: +(" (file-name-nondirectory old-file) ")")
@@ -1975,51 +1993,53 @@ If SAME-FILE is non-nil, do not move to a different Info file."
           (while hl
             (let ((file (nth 0 (car hl)))
                   (node (nth 1 (car hl))))
-              (if (and (string-equal file curr-file)
-                       (string-equal node curr-node))
+              (if (and (equal file curr-file)
+                       (equal node curr-node))
                   (setq p (point)))
-              (insert "* " node ": ("
-                     (propertize (or (file-name-directory file) "") 'invisible t)
-                     (file-name-nondirectory file)
-                      ")" node ".\n"))
+              (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")
+    (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)
-  (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-build-toc 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 2 (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)))))
+  (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-build-toc 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 2 (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."
@@ -2219,16 +2239,18 @@ Because of ambiguities, this should be concatenated with something like
         (setq Info-point-loc
               (if (match-beginning 5)
                   (string-to-number (match-string 5))
-                (buffer-substring (match-beginning 0) (1- (match-beginning 1)))))
+                (buffer-substring-no-properties
+                (match-beginning 0) (1- (match-beginning 1)))))
 ;;; Uncomment next line to use names of cross-references in non-index nodes:
 ;;;       (setq Info-point-loc
 ;;;             (buffer-substring (match-beginning 0) (1- (match-beginning 1))))
       )
     (replace-regexp-in-string
      "[ \n]+" " "
-     (or (match-string 2)
+     (or (match-string-no-properties 2)
         ;; If the node name is the menu entry name (using `entry::').
-        (buffer-substring (match-beginning 0) (1- (match-beginning 1)))))))
+        (buffer-substring-no-properties
+         (match-beginning 0) (1- (match-beginning 1)))))))
 
 ;; No one calls this.
 ;;(defun Info-menu-item-sequence (list)
@@ -2598,6 +2620,15 @@ in other ways.)"
         (t (Info-next-preorder)))
       (scroll-up))))
 
+(defun Info-mouse-scroll-up (e)
+  "Scroll one screenful forward in Info, using the mouse.
+See `Info-scroll-up'."
+  (interactive "e")
+  (save-selected-window
+    (if (eventp e)
+       (select-window (posn-window (event-start e))))
+    (Info-scroll-up)))
+
 (defun Info-scroll-down ()
   "Scroll one screenful back in Info, considering all nodes as one sequence.
 If point is within the menu of a node, and `Info-scroll-prefer-subnodes'
@@ -2624,6 +2655,15 @@ parent node."
        (Info-last-preorder)
       (scroll-down))))
 
+(defun Info-mouse-scroll-down (e)
+  "Scroll one screenful backward in Info, using the mouse.
+See `Info-scroll-down'."
+  (interactive "e")
+  (save-selected-window
+    (if (eventp e)
+       (select-window (posn-window (event-start e))))
+    (Info-scroll-down)))
+
 (defun Info-next-reference (&optional recur)
   "Move cursor to the next cross-reference or menu item in the node."
   (interactive)
@@ -2682,7 +2722,7 @@ following nodes whose names also contain the word \"Index\"."
   (or file (setq file Info-current-file))
   (or (assoc file Info-index-nodes)
       ;; Skip virtual Info files
-      (and (member file '("dir" "history" "toc" "apropos"))
+      (and (member file '("dir" apropos history toc))
            (setq Info-index-nodes (cons (cons file nil) Info-index-nodes)))
       (not (stringp file))
       (if Info-file-supports-index-cookies
@@ -2782,7 +2822,8 @@ Use the \\<Info-mode-map>\\[Info-index-next] command to see the other matches.
 Give an empty topic name to go to the Index node itself."
   (interactive
    (list
-    (let ((Info-complete-menu-buffer (clone-buffer))
+    (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")
@@ -2794,6 +2835,11 @@ Give an empty topic name to go to the Index node itself."
        (kill-buffer Info-complete-menu-buffer)))))
   (if (equal Info-current-file "dir")
       (error "The Info directory node has no index; use m to select a manual"))
+  ;; Strip leading colon in topic; index format does not allow them.
+  (if (and (stringp topic)
+          (> (length topic) 0)
+          (= (aref topic 0) ?:))
+      (setq topic (substring topic 1)))
   (let ((orignode Info-current-node)
        (pattern (format "\n\\* +\\([^\n]*%s[^\n]*\\):[ \t]+\\([^\n]*\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
                         (regexp-quote topic)))
@@ -2856,8 +2902,11 @@ Give an empty topic name to go to the Index node itself."
           (car (car Info-index-alternatives))
           (nth 2 (car Info-index-alternatives))
           (if (cdr Info-index-alternatives)
-              (format "(%s total; use `,' for next)"
-                      (length Info-index-alternatives))
+              (format "(%s total; use `%s' for next)"
+                      (length Info-index-alternatives)
+                      (key-description (where-is-internal
+                                        'Info-index-next overriding-local-map
+                                        t)))
             "(Only match)")))
 
 (defun Info-find-index-name (name)
@@ -2897,11 +2946,20 @@ Build a menu of the possible matches."
          manuals matches node nodes)
       (let ((Info-fontify-maximum-menu-size nil))
        (Info-directory)
+       ;; current-node and current-file are nil when they invoke info-apropos
+       ;; as the first Info command, i.e. info-apropos loads info.el.  In that
+       ;; case, we use (DIR)Top instead, to avoid signalling an error after
+       ;; the search is complete.
+       (when (null current-node)
+         (setq current-file Info-current-file)
+         (setq current-node Info-current-node))
        (message "Searching indices...")
        (goto-char (point-min))
        (re-search-forward "\\* Menu: *\n" nil t)
        (while (re-search-forward "\\*.*: *(\\([^)]+\\))" nil t)
-         (setq manuals (cons (match-string 1) manuals)))
+         ;; add-to-list makes sure we don't have duplicates in `manuals',
+         ;; so that the following dolist loop runs faster.
+         (add-to-list 'manuals (match-string 1)))
        (dolist (manual (nreverse manuals))
          (message "Searching %s" manual)
          (condition-case err
@@ -2924,7 +2982,7 @@ Build a menu of the possible matches."
             (message "%s" (if (eq (car-safe err) 'error)
                               (nth 1 err) err))
             (sit-for 1 t)))))
-      (Info-goto-node (concat "(" current-file ")" current-node))
+      (Info-find-node current-file current-node)
       (setq Info-history ohist
            Info-history-list ohist-list)
       (message "Searching indices...done")
@@ -2943,7 +3001,7 @@ Build a menu of the possible matches."
                     (if (nth 3 entry)
                         (concat " (line " (nth 3 entry) ")")
                       "")))))
-       (Info-find-node "apropos" "Index")
+       (Info-find-node 'apropos "Index")
        (setq Info-complete-cache nil)))))
 
 (defun Info-undefined ()
@@ -3034,7 +3092,11 @@ At end of the node's text, moves to the next node, or up if none."
 (defun Info-follow-nearest-node (&optional fork)
   "Follow a node reference near point.
 If point is on a reference, follow that reference.  Otherwise,
-if point is in a menu item description, follow that menu item."
+if point is in a menu item description, follow that menu item.
+
+If FORK is non-nil (interactively with a prefix arg), show the node in
+a new Info buffer.
+If FORK is a string, it is the name to use for the new buffer."
   (interactive "P")
   (or (Info-try-follow-nearest-node fork)
       (when (save-excursion
@@ -3051,7 +3113,8 @@ if point is in a menu item description, follow that menu item."
 
 ;; Common subroutine.
 (defun Info-try-follow-nearest-node (&optional fork)
-  "Follow a node reference near point.  Return non-nil if successful."
+  "Follow a node reference near point.  Return non-nil if successful.
+If FORK is non-nil, it i spassed to `Info-goto-node'."
   (let (node)
     (cond
      ((Info-get-token (point) "[hf]t?tp://" "[hf]t?tp://\\([^ \t\n\"`({<>})']+\\)")
@@ -3199,16 +3262,20 @@ if point is in a menu item description, follow that menu item."
 (defvar info-tool-bar-map
   (if (display-graphic-p)
       (let ((map (make-sparse-keymap)))
-       (tool-bar-local-item-from-menu 'Info-exit "close" map Info-mode-map)
-       (tool-bar-local-item-from-menu 'Info-history-back "left-arrow" map Info-mode-map)
-       (tool-bar-local-item-from-menu 'Info-history-forward "right-arrow" map Info-mode-map)
-       (tool-bar-local-item-from-menu 'Info-prev "prev-node" map Info-mode-map)
-       (tool-bar-local-item-from-menu 'Info-next "next-node" map Info-mode-map)
+       (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)
@@ -3285,10 +3352,14 @@ With a zero prefix arg, put the name inside a function call to `info'."
   (interactive "P")
   (unless Info-current-node
     (error "No current Info node"))
-  (let ((node (concat "(" (file-name-nondirectory Info-current-file) ")"
-                     Info-current-node)))
+  (let ((node (if (stringp Info-current-file)
+                 (concat "(" (file-name-nondirectory Info-current-file) ")"
+                         Info-current-node))))
     (if (zerop (prefix-numeric-value arg))
         (setq node (concat "(info \"" node "\")")))
+    (unless (stringp Info-current-file)
+      (setq node (format "(Info-find-node '%S '%S)"
+                        Info-current-file Info-current-node)))
     (kill-new node)
     (message "%s" node)))
 
@@ -3352,7 +3423,7 @@ Advanced commands:
 \\[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.
-\\[Info-index] Look up a topic in this manual's Index and move to that index entry.
+\\[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-apropos]       Look for a string in the indices of all manuals.
 \\[Info-goto-node]     Move to node specified by name.
@@ -3396,7 +3467,7 @@ Advanced commands:
   (setq widen-automatically nil)
   (setq desktop-save-buffer 'Info-desktop-buffer-misc-data)
   (add-hook 'kill-buffer-hook 'Info-kill-buffer nil t)
-  (add-hook 'clone-buffer-hook 'Info-clone-buffer-hook nil t)
+  (add-hook 'clone-buffer-hook 'Info-clone-buffer nil t)
   (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
   (add-hook 'isearch-mode-hook 'Info-isearch-start nil t)
   (set (make-local-variable 'isearch-search-fun-function)
@@ -3417,7 +3488,8 @@ Advanced commands:
        Info-tag-table-buffer
        (kill-buffer Info-tag-table-buffer)))
 
-(defun Info-clone-buffer-hook ()
+;; Placed on `clone-buffer-hook'.
+(defun Info-clone-buffer ()
   (when (bufferp Info-tag-table-buffer)
     (setq Info-tag-table-buffer
          (with-current-buffer Info-tag-table-buffer (clone-buffer))))
@@ -3666,6 +3738,7 @@ the variable `Info-file-list-for-emacs'."
            (fontify-visited-p ; visited nodes need to be re-fontified
             (and Info-fontify-visited-nodes
                  ;; Don't take time to refontify visited nodes in huge nodes
+                Info-fontify-maximum-menu-size
                  (< (- (point-max) (point-min)) Info-fontify-maximum-menu-size)))
            rbeg rend)
 
@@ -3774,6 +3847,8 @@ the variable `Info-file-list-for-emacs'."
                   (setq other-tag
                        (cond ((save-match-data (looking-back "\\<see"))
                               "")
+                             ((save-match-data (looking-back "\\<in"))
+                              "")
                              ((memq (char-before) '(nil ?\. ?! ??))
                                "See ")
                              ((save-match-data
@@ -3815,29 +3890,30 @@ the variable `Info-file-list-for-emacs'."
                                         "^[ \t]+" ""
                                         (replace-regexp-in-string
                                          "[ \t\n]+" " "
-                                         (or (match-string 5)
+                                         (or (match-string-no-properties 5)
                                              (and (not (equal (match-string 4) ""))
-                                                  (match-string 4))
-                                             (match-string 2)))))
+                                                  (match-string-no-properties 4))
+                                             (match-string-no-properties 2)))))
                                 (external-link-p
                                  (string-match "(\\([^)]+\\))\\([^)]*\\)" node))
                                  (file (if external-link-p
                                           (file-name-nondirectory
-                                           (match-string 1 node))
+                                           (match-string-no-properties 1 node))
                                         Info-current-file))
                                  (hl Info-history-list)
                                  res)
                             (if external-link-p
                                (setq node (if (equal (match-string 2 node) "")
                                                "Top"
-                                             (match-string 2 node))))
+                                             (match-string-no-properties 2 node))))
                            (while hl
                              (if (and (string-equal node (nth 1 (car hl)))
-                                      (string-equal
-                                       file (if external-link-p
-                                                (file-name-nondirectory
-                                                 (caar hl))
-                                              (caar hl))))
+                                      (equal file
+                                             (if (and external-link-p
+                                                      (stringp (caar hl)))
+                                                 (file-name-nondirectory
+                                                  (caar hl))
+                                               (caar hl))))
                                  (setq res (car hl) hl nil)
                                (setq hl (cdr hl))))
                             res))) 'info-xref-visited 'info-xref))
@@ -3897,8 +3973,8 @@ the variable `Info-file-list-for-emacs'."
       (goto-char (point-min))
       (when (and (or not-fontified-p fontify-visited-p)
                  (search-forward "\n* Menu:" nil t)
-                 (not (Info-index-node))
                  ;; Don't take time to annotate huge menus
+                Info-fontify-maximum-menu-size
                  (< (- (point-max) (point)) Info-fontify-maximum-menu-size))
         (let ((n 0)
               cont)
@@ -3930,30 +4006,34 @@ the variable `Info-file-list-for-emacs'."
                  (if (and Info-fontify-visited-nodes
                           (save-match-data
                             (let* ((node (if (equal (match-string 3) "")
-                                            (match-string 1)
-                                          (match-string 3)))
+                                            (match-string-no-properties 1)
+                                          (match-string-no-properties 3)))
                                   (external-link-p
                                    (string-match "(\\([^)]+\\))\\([^)]*\\)" node))
                                   (file (if external-link-p
                                             (file-name-nondirectory
-                                             (match-string 1 node))
+                                             (match-string-no-properties 1 node))
                                           Info-current-file))
                                   (hl Info-history-list)
                                   res)
                               (if external-link-p
                                   (setq node (if (equal (match-string 2 node) "")
                                                  "Top"
-                                               (match-string 2 node))))
+                                               (match-string-no-properties 2 node))))
                              (while hl
                                (if (and (string-equal node (nth 1 (car hl)))
-                                        (string-equal
-                                         file (if external-link-p
-                                                  (file-name-nondirectory (caar hl))
-                                                (caar hl))))
+                                        (equal file
+                                               (if (and external-link-p
+                                                        (stringp (caar hl)))
+                                                   (file-name-nondirectory
+                                                    (caar hl))
+                                                 (caar hl))))
                                    (setq res (car hl) hl nil)
                                  (setq hl (cdr hl))))
                               res))) 'info-xref-visited 'info-xref)))
-             (when (and not-fontified-p (memq Info-hide-note-references '(t hide)))
+             (when (and not-fontified-p
+                        (memq Info-hide-note-references '(t hide))
+                        (not (Info-index-node)))
                (put-text-property (match-beginning 2) (1- (match-end 6))
                                   'invisible t)
                ;; Unhide the file name in parens
@@ -3999,7 +4079,7 @@ the variable `Info-file-list-for-emacs'."
       ;; Fontify http and ftp references
       (goto-char (point-min))
       (when not-fontified-p
-        (while (re-search-forward "[hf]t?tp://[^ \t\n\"`({<>})']+" nil t)
+        (while (re-search-forward "\\(https?\\|ftp\\)://[^ \t\n\"`({<>})']+" nil t)
           (add-text-properties (match-beginning 0) (match-end 0)
                                '(font-lock-face info-xref
                                                 mouse-face highlight
@@ -4208,8 +4288,8 @@ BUFFER is the buffer speedbar is requesting buttons for."
 
 (defun Info-desktop-buffer-misc-data (desktop-dirname)
   "Auxiliary information to be saved in desktop file."
-  (if (not (member Info-current-file '("apropos" "history" "toc")))
-      (list Info-current-file Info-current-node)))
+  (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
                                     desktop-buffer-name