diff lisp/packages/info.el @ 181:bfd6434d15b3 r20-3b17

Import from CVS: tag r20-3b17
author cvs
date Mon, 13 Aug 2007 09:53:19 +0200
parents 6075d714658b
children e121b013d1f0
line wrap: on
line diff
--- a/lisp/packages/info.el	Mon Aug 13 09:52:21 2007 +0200
+++ b/lisp/packages/info.el	Mon Aug 13 09:53:19 2007 +0200
@@ -1,7 +1,7 @@
 ;;; info.el --- info package for Emacs.
 ;; Keywords: help
 
-;; Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1993, 1997 Free Software Foundation, Inc.
 
 ;; Author: Dave Gillespie <daveg@synaptics.com>
 ;;	   Richard Stallman <rms@gnu.ai.mit.edu>
@@ -301,6 +301,7 @@
 ;;
 ;; Added `Info-minibuffer-history'
 ;; (also added to defaults in "lisp/utils/savehist.el")
+;;  Other changes in main ChangeLog.
 
 ;; Code:
 
@@ -367,9 +368,17 @@
   :group 'info)
 
 (defcustom Info-default-directory-list nil
-  "*List of default directories to search for Info documentation files.
-This value is used as the default for `Info-directory-list'.  It is set
-in startup.el."
+  "*List of default directories to search for Info documentation
+files.  This value is used as the default for `Info-directory-list'.
+It is set in startup.el."
+  :type '(repeat directory)
+  :group 'info)
+
+(defcustom Info-additional-directory-list nil
+  "List of additional directories to search for Info documentation
+files.  These directories are not searched for merging the `dir'
+file. An example might be something like:
+\"/usr/local/lib/xemacs/packages/lisp/calc/\""
   :type '(repeat directory)
   :group 'info)
 
@@ -379,7 +388,7 @@
 	(let ((list nil)
  	      idx)
 	  (while (> (length path) 0)
-	    (setq idx (or (string-match ":" path) (length path))
+	    (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)))))
@@ -389,12 +398,15 @@
 Default is to use the environment variable INFOPATH if it exists,
 else to use Info-default-directory-list.")
 
-(defvar Info-suffix-list '( (".info" . nil)
+;; Is this right for NT?  .zip, with -c for to stdout, right?
+(defvar Info-suffix-list '( ("" . nil) 
+			    (".info" . nil)
 			    (".info.gz" . "gzip -dc %s")
 			    (".info-z" . "gzip -dc %s")
 			    (".info.Z" . "uncompress -c %s")
 			    (".gz" . "gzip -dc %s")
-			    (".Z" . "uncompress -c %s") )
+			    (".Z" . "uncompress -c %s")
+			    (".zip" . "unzip -c %s") )
   "List of file name suffixes and associated decoding commands.
 Each entry should be (SUFFIX . STRING); if STRING contains %s, that is
 changed to name of the file to decode, otherwise the file is given to
@@ -405,7 +417,9 @@
 All \"*Note\" references will be changed to use this word instead.")
 
 (defvar Info-current-file nil
-  "Info file that Info is now looking at, or 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.")
 
 (defvar Info-current-subfile nil
   "Info subfile that is actually in the *info* buffer now,
@@ -428,7 +442,8 @@
   "List of possible matches for last Info-index command.")
 (defvar Info-index-first-alternative nil)
 
-(defcustom Info-annotations-path '("~/.infonotes" "/usr/lib/info.notes")
+(defcustom Info-annotations-path '("~/.xemacs/info.notes"
+				   "/usr/lib/info.notes")
   "*Names of files that contain annotations for different Info nodes.
 By convention, the first one should reside in your personal directory.
 The last should be a world-writable \"public\" annotations file."
@@ -467,7 +482,7 @@
 	   (setq file (nth 2 p))
 	   (setq command-line-args-left nil))
       (setq p (cdr p))))
-;  (Info-setup-x)
+;  (Info-setup-x) ??? What was this going to be?  Can anyone tell karlheg?
   (if file
       (unwind-protect
 	  (Info-goto-node (concat "(" file ")"))
@@ -492,18 +507,16 @@
 	  (bury-buffer (find-file-noselect (car f))))
       (setq f (cdr f)))))
 
-(defconst Info-emacs-info-file-name "xemacs")
-
-;; 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 &optional nodename no-going-back tryfile line)
-  ;; Look for a plausible filename, or if not found then look for URls
-  ;; &c, and dispatch to the appropriate fn.
+  "Go to an info node specified as separate FILENAME and NODENAME.
+Look for a plausible filename, or if not found then look for URL's and
+dispatch to the appropriate fn.  NO-GOING-BACK is non-nil if
+recovering from an error in this function; it says do not attempt
+further (recursive) error recovery.  TRYFILE is ??"
 
   (Info-setup-initial)
 
-  (cond 
+  (cond
    ;; empty filename is simple case
    ((null filename)
     (Info-find-file-node nil nodename no-going-back tryfile line))
@@ -511,18 +524,15 @@
    ;; Expand it, look harder...
    ((let (temp temp-downcase found 
 	       (fname (substitute-in-file-name filename)))
-      ;; horrible kludge so that I can call the emacs doc
-      ;; "XEmacs" without having to make .../info/dir be ugly.
-      ;; I'd like to do this only if the "emacs" node wasn't
-      ;; found, but this 200+ line function is too hairy for me
-      ;; to want to think about any longer than I have to.
-      (if (equal (downcase fname) "emacs")
-	  (setq fname Info-emacs-info-file-name))
-      (let ((dirs (if (string-match "^\\./" fname)
-		      ;; If specified name starts with `./'
-		      ;; then just try current directory.
-		      (list default-directory) ; '("./")
-		    Info-directory-list)))
+      (let ((dirs (cond
+		   ((string-match "^\\./" fname) ; If specified name starts with `./'
+		    (list default-directory)) ; then just try current directory.
+		   ((file-name-absolute-p fname)
+		    '(nil))		; No point in searching for an absolute file name
+		   (Info-additional-directory-list
+		    (append Info-directory-list
+			    Info-additional-directory-list))
+		   (t Info-directory-list))))
 	;; Search the directory list for file FNAME.
 	(while (and dirs (not found))
 	  (setq temp (expand-file-name fname (car dirs)))
@@ -539,29 +549,32 @@
     (Info-find-file-node filename nodename no-going-back tryfile line))
    ;; Look for a URL.  This pattern is stolen from w3.el to prevent
    ;; loading it if we won't need it.
-   ((string-match  "^\\(wais\\|solo\\|x-exec\\|newspost\\|www\\|mailto\\|news\\|tn3270\\|ftp\\|http\\|file\\|telnet\\|gopher\\):" filename)
-    (w3-fetch filename))
+   ((string-match  (concat "^\\(wais\\|solo\\|x-exec\\|newspost\\|www\\|"
+			   "mailto\\|news\\|tn3270\\|ftp\\|http\\|file\\|"
+			   "telnet\\|gopher\\):")
+		   filename)
+    (browse-url filename))
    (t
     (error "Info file %s does not exist" filename))))
 
-(defun Info-find-file-node (filename nodename 
+(defun Info-find-file-node (filename nodename
 				     &optional no-going-back tryfile line)
   ;; This is the guts of what was Info-find-node. Whoever wrote this
   ;; should be locked up where they can't do any more harm.
 
   ;; Go into info buffer.
   (switch-to-buffer "*info*")
-  (if (fboundp 'buffer-disable-undo)
-      (buffer-disable-undo (current-buffer)))
+  (buffer-disable-undo (current-buffer))
   (run-hooks 'Info-startup-hook)
   (or (eq major-mode 'Info-mode)
       (Info-mode))
   (or (null filename)
       (equal Info-current-file filename)
       (not Info-novice)
-      (string-match "^dir$" (file-name-nondirectory Info-current-file))
-      (if (y-or-n-p (format "Leave Info file `%s'? "
-			    (file-name-nondirectory Info-current-file)))
+      (string= "dir" (file-name-nondirectory Info-current-file))
+      (if (y-or-n-p-maybe-dialog-box
+	   (format "Leave Info file `%s'? "
+		   (file-name-nondirectory Info-current-file)))
 	  (message "")
 	(keyboard-quit)))
   ;; Record the node we are leaving.
@@ -578,55 +591,15 @@
 	    (let ((buffer-read-only nil))
 	      (setq Info-current-file nil
 		    Info-current-subfile nil
+		    Info-current-file-completions nil
 		    Info-index-alternatives nil
-		    Info-current-file-completions nil
 		    buffer-file-name nil)
 	      (erase-buffer)
-	      (Info-insert-file-contents filename t)
-	      ;; Add all "localdir" files in search path to "dir" file.
-	      (if (string-match "^dir$" (file-name-nondirectory filename))
-		  (let ((d Info-directory-list)
-			name (lim -1))
-		    (goto-char (point-max))
-		    (if (re-search-backward "^ *\\* *Locals *: *\n" nil t)
-			(delete-region (match-beginning 0) (match-end 0))
-		      (search-backward "\^L" nil t))
-		    (while d
-		      (setq name (expand-file-name "localdir" (car d)))
-		      (if (or (file-exists-p name)
-			      (file-exists-p
-			       (setq name (concat name ".info"))))
-			  ;; Insert menu part of the file
-			  (let* ((pt (point))
-				 (len (nth 1 (insert-file-contents name))))
-			    ;; be careful to put the local info entries
-			    ;; in the buffer in the order they were found
-			    ;; in the search path.
-			    (goto-char (+ pt len))
-			    (save-excursion
-			      (goto-char pt)
-			      (if (search-forward "* menu:" (+ pt len) t)
-				  (progn
-				    (forward-line 1)
-				    (delete-region pt (point)))))))
-		      (setq d (cdr d)))
-		    ;; Eliminate redundant menu entries.
-		    (goto-char (point-min))
-		    (while (re-search-forward "\n\\* \\([^:\n]*\\):" nil t)
-		      (let ((str (buffer-substring (match-beginning 1)
-						   (match-end 1))))
-			(if (> (point) lim)
-			    (save-excursion
-			      (setq lim (if (search-forward "\^_" nil t)
-					    (point)
-					  (point-max)))))
-			(save-excursion
-			  (if (search-forward (format "\n* %s:" str) lim t)
-			      (let ((pt (- (point) 3 (length str))))
-				(forward-line 1)
-				(delete-region pt (point)))))))))
+	      (if (string= "dir" (file-name-nondirectory filename))
+		  (Info-insert-dir)
+		(Info-insert-file-contents filename t)
+		(setq default-directory (file-name-directory filename)))
 	      (set-buffer-modified-p nil)
-	      (setq default-directory (file-name-directory filename))
 	      ;; See whether file has a tag table.  Record the location if yes.
 	      (set-marker Info-tag-table-marker nil)
 	      (goto-char (point-max))
@@ -647,8 +620,7 @@
 			  (let ((buf (current-buffer)))
 			    (set-buffer
 			     (get-buffer-create " *info tag table*"))
-			    (if (fboundp 'buffer-disable-undo)
-				(buffer-disable-undo (current-buffer)))
+			    (buffer-disable-undo (current-buffer))
 			    (setq case-fold-search t)
 			    (erase-buffer)
 			    (insert-buffer-substring buf)
@@ -736,6 +708,191 @@
 	  (Info-goto-node (car hist) t)
 	  (goto-char (+ (point-min) (nth 1 hist)))))))
 
+;; Cache the contents of the (virtual) dir file, once we have merged
+;; it for the first time, so we can save time subsequently.
+(defvar Info-dir-contents nil)
+
+;; Cache for the directory we decided to use for the default-directory
+;; of the merged dir text.
+(defvar Info-dir-contents-directory nil)
+
+;; Record the file attributes of all the files from which we
+;; constructed Info-dir-contents.
+(defvar Info-dir-file-attributes nil)
+
+(defun Info-insert-dir ()
+  "Construct the Info directory node by merging the files named
+\"dir\" or \"localdir\" from the directories in `Info-directory-list'
+The \"dir\" files will take precedence in cases where both exist.  It
+sets the *info* buffer's `default-directory' to the first directory we
+actually get any text from."
+  (if (and Info-dir-contents Info-dir-file-attributes
+	   ;; Verify that none of the files we used has changed
+	   ;; since we used it.
+	   (eval (cons 'and
+		       (mapcar '(lambda (elt)
+				  (let ((curr (file-attributes (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)
+    (let ((dirs Info-directory-list)
+	  buffers buffer others nodes dirs-done)
+
+      (setq Info-dir-file-attributes nil)
+
+      ;; Search the directory list for the directory file.
+      (while dirs
+	(let ((truename (file-truename (expand-file-name (car dirs)))))
+	  (or (member truename dirs-done)
+	      (member (directory-file-name truename) dirs-done)
+	      ;; Try several variants of specified name.
+	      ;; Try upcasing, appending `.info', or both.
+	      (let* (file
+		     (attrs
+		      (or
+		       (progn (setq file (expand-file-name "dir" truename))
+			      (file-attributes file))
+		       (progn (setq file (expand-file-name "DIR" truename))
+			      (file-attributes file))
+		       (progn (setq file (expand-file-name "dir.info" truename))
+			      (file-attributes file))
+		       (progn (setq file (expand-file-name "DIR.INFO" truename))
+			      (file-attributes file))
+		       (progn (setq file (expand-file-name "localdir" truename))
+			      (file-attributes file))
+		       )))
+		(setq dirs-done
+		      (cons truename
+			    (cons (directory-file-name truename)
+				  dirs-done)))
+		(if attrs
+		    (save-excursion
+		      (or buffers
+			  (message "Composing main Info directory..."))
+		      (set-buffer (generate-new-buffer "info dir"))
+		      (when (string-match "localdir" file)
+			(insert "localdir\n"))
+		      (insert-file-contents file)
+		      (setq buffers (cons (current-buffer) buffers)
+			    Info-dir-file-attributes
+			    (cons (cons file attrs)
+				  Info-dir-file-attributes))))))
+	  (or (cdr dirs) (setq Info-dir-contents-directory (car dirs)))
+	  (setq dirs (cdr dirs))))
+      
+      (or buffers
+	  (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))
+
+      ;; Insert the entire original dir file as a start; note that we've
+      ;; already saved its default directory to use as the default
+      ;; directory for the whole concatenation.
+      (insert-buffer buffer)
+
+      ;; Look at each of the other buffers one by one.
+      (while others
+	(let ((other (car others))
+	      (info-buffer (current-buffer)))
+	  (if (with-current-buffer other
+		(goto-char (point-min))
+		(when (looking-at "localdir")
+		  (forward-line 1)
+		  (delete-region (point-min) (point))
+		  t))		
+	      (save-excursion
+		(set-buffer info-buffer)
+		(goto-char (point-max))
+		(cond
+		 ((re-search-backward "^ *\\* *Locals *: *\n" nil t)
+		  (delete-region (match-beginning 0) (match-end 0)))
+		 ((re-search-backward "^Local" nil t)
+		  (end-of-line))
+		 (t (search-backward "\^L" nil t)))
+		;; Insert menu part of the file
+		(let* ((pt (point))
+		       (len (length (buffer-string nil nil other))))
+		  (insert "\n" (buffer-string nil nil other))
+		  (goto-char (+ pt len))
+		  (save-excursion
+		    (goto-char pt)
+		    (if (search-forward "* menu:" (+ pt len) t)
+			(progn
+			  (forward-line 1)
+			  (delete-region pt (point)))))))
+	    ;; In each, find all the menus.
+	    (save-excursion
+	      (set-buffer other)
+	      (goto-char (point-min))
+	      ;; Find each menu, and add an elt to NODES for it.
+	      (while (re-search-forward "^\\* Menu:" nil t)
+		(let (beg nodename end)
+		  (forward-line 1)
+		  (setq beg (point))
+		  (search-backward "\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 others (cdr others))))
+      
+      ;; Add to the main menu a menu item for each other node.
+      (re-search-forward "^\\* Menu:")
+      (forward-line 1)
+      (let ((menu-items '("top"))
+	    (nodes nodes)
+	    (case-fold-search t)
+	    (end (save-excursion (search-forward "\^_" nil t) (point))))
+	(while nodes
+	  (let ((nodename (car (car nodes))))
+	    (save-excursion
+	      (or (member (downcase nodename) menu-items)
+		  (re-search-forward (concat "^\\* "
+					     (regexp-quote nodename)
+					     "::")
+				     end t)
+		  (progn
+		    (insert "* " nodename "::" "\n")
+		    (setq menu-items (cons nodename menu-items))))))
+	  (setq nodes (cdr nodes))))
+      ;; Now take each node of each of the other buffers
+      ;; and merge it into the main buffer.
+      (while nodes
+	(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: "
+					 (regexp-quote nodename)
+					 "[,\n\t]")
+				 nil t)
+	      (progn
+		(search-forward "\n\^_" nil 'move)
+		(beginning-of-line)
+		(insert "\n"))
+	    ;; If none exists, add one.
+	    (goto-char (point-max))
+	    (insert "\^_\nFile: dir\tNode: " nodename "\n\n* Menu:\n\n"))
+	  ;; Merge the text from the other buffer's menu
+	  ;; into the menu in the like-named node in the main buffer.
+	  (apply 'insert-buffer-substring (cdr (car nodes))))
+	(setq nodes (cdr nodes)))
+      ;; Kill all the buffers we just made.
+      (while buffers
+	(kill-buffer (car buffers))
+	(setq buffers (cdr buffers)))
+      (message "Composing main Info directory...done"))
+    (setq Info-dir-contents (buffer-string)))
+  (setq default-directory Info-dir-contents-directory)
+  (setq buffer-file-name (caar Info-dir-file-attributes)))
+
 (defun Info-history-add (file node point)
   (if Info-keeping-history
       (let* ((name (format "(%s)%s" (Info-file-name-only file) node))
@@ -797,17 +954,27 @@
     (+ (- nodepos lastfilepos) (point))))
 
 (defun Info-suffixed-file (name &optional name2)
+  "Look for NAME with each of the `Info-suffix-list' extensions in
+turn. Optional NAME2 is the name of a fallback info file to check
+for; usually a downcased version of NAME."
   (let ((suff Info-suffix-list)
-	(found nil))
+	(found nil)
+	file file2)
     (while (and suff (not found))
-      (if (file-exists-p (concat name (car (car suff))))
-	  (setq found (concat name (car (car suff))))
-	(if (and name2 (file-exists-p (concat name2 (car (car suff)))))
-	    (setq found (concat name2 (car (car suff))))
-	  (setq suff (cdr suff)))))
+      (setq file (concat name (caar suff))
+	    file2 (and name2 (concat name2 (caar suff))))
+      (cond
+       ((file-exists-p file)
+	(setq found file))
+       ((and file2 (file-exists-p file2))
+	(setq found file2))
+       (t
+	(setq suff (cdr suff)))))
     (or found
-	(and (file-exists-p name) name)
-	(and name2 (file-exists-p name2) name2))))
+	(and name (when (file-exists-p name)
+		    name))
+	(and name2 (when (file-exists-p name2)
+		     name2)))))
 
 (defun Info-insert-file-contents (file &optional visit)
   (setq file (expand-file-name file default-directory))
@@ -892,7 +1059,7 @@
 		       "")
 		     ")"
 		     (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.
 
@@ -1017,6 +1184,7 @@
 (defvar Info-last-search nil
   "Default regexp for \\<Info-mode-map>\\[Info-search] command to search for.")
 
+
 ;;;###autoload
 (defun Info-search (regexp)
   "Search for REGEXP, starting from point, and select node it's found in."
@@ -1081,14 +1249,15 @@
       (or (and (equal onode Info-current-node)
                (equal ofile Info-current-file))
           (Info-history-add ofile onode opoint)))))
-
+
+
 ;; Extract the value of the node-pointer named NAME.
 ;; If there is none, use ERRORNAME in the error message; 
 ;; if ERRORNAME is nil, just return nil.
 (defun Info-extract-pointer (name &optional errorname)
   (save-excursion
    (goto-char (point-min))
-   (forward-line 1)
+   (forward-line 4)
    (let ((case-fold-search t))
      (if (re-search-backward (concat name ":") nil t)
 	 (progn
@@ -1169,7 +1338,7 @@
   "Go to the Info directory node."
   (interactive)
   (Info-find-node "dir" "top"))
-
+
 (defun Info-follow-reference (footnotename)
   "Follow cross reference named NAME to the node it refers to.
 NAME may be an abbreviation of the reference name."
@@ -1644,6 +1813,7 @@
     (Info-index (symbol-name command)))
   (pop-to-buffer "*info*"))
 
+
 ;;;###autoload
 (defun Info-goto-emacs-command-node (key)
   "Look up an Emacs command in the Emacs manual in the Info system.
@@ -1782,11 +1952,11 @@
 
 (defun Info-annotate (arg)
   "Add a personal annotation to the current Info node.
-Only you will be able to see this annotation.
-Annotations are stored in the file ~/.infonotes by default.
-If point is inside an existing annotation, edit that annotation.
-A prefix argument specifies which annotations file (from
-Info-annotations-path) is to be edited; default is 1."
+ Only you will be able to see this annotation.  Annotations are stored
+in the file \"~/.xemacs/info.notes\" by default.  If point is inside
+an existing annotation, edit that annotation.  A prefix argument
+specifies which annotations file (from `Info-annotations-path') is to
+be edited; default is 1."
   (interactive "p")
   (setq arg (1- arg))
   (if (or (< arg 0) (not (nth arg Info-annotations-path)))
@@ -1890,7 +2060,8 @@
       (or (equal tag "")
 	  (insert "<<" tag ">>"))))
   (Info-cease-annotate))
-
+
+
 (defun Info-exit ()
   "Exit Info by selecting some other buffer."
   (interactive)
@@ -2229,7 +2400,7 @@
   "Local keymap used within `e' command of Info.")
 (if Info-edit-map
     nil
-  ;; XEmcas: remove FSF stuff
+  ;; XEmacs: remove FSF stuff
   (setq Info-edit-map (make-sparse-keymap))
   (set-keymap-name Info-edit-map 'Info-edit-map)
   (set-keymap-parents Info-edit-map (list text-mode-map))
@@ -2266,7 +2437,7 @@
   (interactive)
   ;; Do this first, so nothing has changed if user C-g's at query.
   (and (buffer-modified-p)
-       (y-or-n-p "Save the file? ")
+       (y-or-n-p-maybe-dialog-box "Save the file? ")
        (save-buffer))
   (use-local-map Info-mode-map)
   (setq major-mode 'Info-mode)
@@ -2289,6 +2460,7 @@
     (save-excursion
       (Info-find-node "XEmacs" "Command Index")
       ;; Take the index node off the Info history.
+      ;; ??? says this isn't safe someplace else... hmmm.
       (setq Info-history (cdr Info-history))
       (goto-char (point-max))
       (while (re-search-backward cmd-desc nil t)
@@ -2304,52 +2476,81 @@
 ;;; fontification and mousability for info
 
 (defun Info-highlight-region (start end face)
-  (let ((extent (make-extent start end)))
+  (let ((extent nil)
+	(splitp (string-match "\n[ \t]+" (buffer-substring start end))))
+    (if splitp
+	(save-excursion
+	  (setq extent (make-extent start (progn (goto-char start)
+						 (end-of-line)
+						 (point))))
+	  (set-extent-face extent face)
+	  (set-extent-property extent 'info t)
+	  (set-extent-property extent 'highlight t)
+	  (skip-chars-forward "\n\t ")
+	  (setq extent (make-extent (point) end)))
+      (setq extent (make-extent start end)))
     (set-extent-face extent face)
     (set-extent-property extent 'info t)
     (set-extent-property extent 'highlight t)))
 
 (defun Info-fontify-node ()
   (save-excursion
-    (let (;(lucid (string-match "Lucid" emacs-version))
-	  (case-fold-search t)
-	  (xref-regexp (concat "\\*" 
+    (let ((case-fold-search t)
+	  (xref-regexp (concat "\\*"
 			       (regexp-quote Info-footnote-tag)
 			       "[ \n\t]*\\([^:]*\\):")))
-;      (if lucid
-	  (map-extents (function (lambda (x y) (delete-extent x)))
-		       (current-buffer) (point-min) (point-max) nil)
-;	)
+      ;; Clear the old extents
+      (map-extents #'(lambda (x y) (delete-extent x))
+		   (current-buffer) (point-min) (point-max) nil)
+      ;; Break the top line iff it is > 79 characters.  Some info nodes
+      ;; have top lines that span 3 lines because of long node titles.
+      ;; eg: (Info-find-node "lispref.info" "Window-Level Event Position Info")
+      (toggle-read-only -1)
+      (let ((extent nil)
+	    (len 0)
+	    (done nil)
+	    (p (point-min)))
+	(goto-char (point-min))
+	(re-search-forward "Node: *[^,]+,  " nil t)
+	(setq len (- (point) (point-min))
+	      extent (make-extent (point-min) (point)))
+	(set-extent-property extent 'invisible t)
+	(while (not done)
+	  (goto-char p)
+	  (end-of-line)
+	  (if (< (current-column) (+ 78 len))
+	      (setq done t)
+	    (goto-char p)
+	    (forward-char (+ 79 len))
+	    (re-search-backward "," nil t)
+	    (forward-char 1)
+	    (insert "\n")
+	    (just-one-space)
+	    (backward-delete-char 1)
+	    (setq p (point)
+		  len 0))))
+      (toggle-read-only 1)
+      ;; Highlight xrefs in the top few lines of the node
       (goto-char (point-min))
       (if (looking-at "^File: [^,: \t]+,?[ \t]+")
 	  (progn
 	    (goto-char (match-end 0))
 	    (while
-		(looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?")
+		(looking-at "[ \t]*[^:, \t\n]+:[ \t]+\\([^:,\t\n]+\\),?\n?")
 	      (goto-char (match-end 0))
-	      (Info-highlight-region (match-beginning 1) (match-end 1)
-				     'info-xref ;lucid
-				     ))))
+	      (Info-highlight-region (match-beginning 1) (match-end 1) 'info-xref))))
+      ;; Now get the xrefs in the body
       (goto-char (point-min))
       (while (re-search-forward xref-regexp nil t)
 	(if (= (char-after (1- (match-beginning 0))) ?\") ; hack
 	    nil
-	  (Info-highlight-region (match-beginning 1) (match-end 1)
-				 'info-xref ;lucid
-				 )))
+	  (Info-highlight-region (match-beginning 1) (match-end 1) 'info-xref)))
+      ;; then highlight the nodes in the menu.
       (goto-char (point-min))
-      (if (and (search-forward "\n* menu:" nil t)
-;; principle of least astonishment, dude...
-;; (Also, in xemacs this is fast even on indexes, and without it, nodes don't
-;; highlight when you move over them.)
-;;	       (not (string-match "\\<Index\\>" Info-current-node))
-;;	       (< (- (point-max) (point)) 10000)
-	       )
+      (if (and (search-forward "\n* menu:" nil t))
 	  (while (re-search-forward
-		  "^\\* \\([^\t\n]*\\):?:[ \t\n]" nil t)
-	    (Info-highlight-region (match-beginning 1) (match-end 1)
-				   'info-node ;lucid
-				   )))
+		  "^\\* \\([^:\t\n]*\\):?:[ \t\n]" nil t)
+	    (Info-highlight-region (match-beginning 1) (match-end 1) 'info-node)))
       (set-buffer-modified-p nil))))
 
 (defun Info-construct-menu (&optional event)
@@ -2361,56 +2562,68 @@
 	(xref-regexp (concat "\\*" 
 			     (regexp-quote Info-footnote-tag)
 			     "[ \n\t]*\\([^:]*\\):"))
-	up-p prev-p next-p menu
-	i text xrefs subnodes in)
+	up-p prev-p next-p menu xrefs subnodes in)
     (save-excursion
-      (goto-char (point-min))
-      (if (looking-at ".*\\bNext:") (setq next-p t))
-      (if (looking-at ".*\\bPrev:") (setq prev-p t))
-      (if (looking-at ".*Up:") (setq up-p t))
-      (setq menu (nconc 
-			(if (setq in (Info-indicated-node event))
-			    (list (vector (car (cdr in)) in t)))
-			(list
-			 ["Goto Info Top-level" Info-directory t]
-			 (vector "Next Node" 'Info-next next-p)
-			 (vector "Previous Node" 'Info-prev prev-p)
-			 (vector "Parent Node (Up)" 'Info-up up-p)
-			 ["Goto Node..." Info-goto-node t]
-			 ["Goto Last Visited Node" Info-last t])))
-      (while (re-search-forward xref-regexp nil t)
-	(setq text (buffer-substring (match-beginning 1) (match-end 1)))
-	(while (setq i (string-match "[ \n\t]+" text i))
-	  (setq text (concat (substring text 0 i) " "
-			     (substring text (match-end 0))))
-	  (setq i (1+ i)))
-	(setq xrefs (cons text xrefs)))
+      ;; `one-space' fixes "Notes:" xrefs that are split across lines.
+      (flet
+	  ((one-space (text)
+		      (let (i)
+			(while (setq i (string-match "[ \n\t]+" text i))
+			  (setq text (concat (substring text 0 i) " "
+					     (substring text (match-end 0))))
+			  (setq i (1+ i)))
+			text)))
+	(goto-char (point-min))
+	(if (looking-at ".*\\bNext:") (setq next-p t))
+	(if (looking-at ".*\\bPrev:") (setq prev-p t))
+	(if (looking-at ".*Up:") (setq up-p t))
+	(setq menu (nconc
+		    (if (setq in (Info-indicated-node event))
+			(list (vector (one-space (cadr in)) in t)
+			      "--:shadowEtchedIn"))
+		    (list
+		     ["Goto Info Top-level" Info-directory t]
+		     (vector "Next Node" 'Info-next next-p)
+		     (vector "Previous Node" 'Info-prev prev-p)
+		     (vector "Parent Node (Up)" 'Info-up up-p)
+		     ["Goto Node..." Info-goto-node t]
+		     ["Goto Last Visited Node " Info-last t])))
+	;; Find the xrefs and make a list
+	(while (re-search-forward xref-regexp nil t)
+	  (setq xrefs (cons (one-space (buffer-substring (match-beginning 1)
+							 (match-end 1)))
+			    xrefs))))
       (setq xrefs (nreverse xrefs))
       (if (> (length xrefs) 21) (setcdr (nthcdr 20 xrefs) '(more)))
+      ;; Find the subnodes and make a list
       (goto-char (point-min))
       (if (search-forward "\n* menu:" nil t)
-	  (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
-	    (setq text (buffer-substring (match-beginning 1) (match-end 1)))
-	    (setq subnodes (cons text subnodes))))
+      (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
+	(setq subnodes (cons (buffer-substring (match-beginning 1)
+					       (match-end 1))
+			     subnodes))))
       (setq subnodes (nreverse subnodes))
-      (if (> (length subnodes) 21) (setcdr (nthcdr 20 subnodes) '(more)))
-      )
+      (if (> (length subnodes) 21) (setcdr (nthcdr 20 subnodes) '(more))))
     (if xrefs
-	(nconc menu (list "----" "Cross-References:" "----")
-	       (mapcar (function (lambda (xref)
-				   (if (eq xref 'more)
-				       "...more..."
-				     (vector xref
-					     (list 'Info-follow-reference xref)
-					     t))))
+	(nconc menu (list "--:shadowDoubleEtchedIn"
+			  "    Cross-References"
+			  "--:singleLine")
+	       (mapcar #'(lambda (xref)
+			   (if (eq xref 'more)
+			       "...more..."
+			     (vector xref
+				     (list 'Info-follow-reference xref)
+				     t)))
 		       xrefs)))
     (if subnodes
-	(nconc menu (list "----" "Sub-Nodes:" "----")
-	       (mapcar (function (lambda (node)
-				   (if (eq node 'more)
-				       "...more..."
-				     (vector node (list 'Info-menu node)
-					     t))))
+	(nconc menu (list "--:shadowDoubleEtchedIn"
+			  "      Sub-Nodes"
+			  "--:singleLine")
+	       (mapcar #'(lambda (node)
+			   (if (eq node 'more)
+			       "...more..."
+			     (vector node (list 'Info-menu node)
+				     t)))
 		       subnodes)))
     menu))
 
@@ -2423,8 +2636,9 @@
   (interactive "e")
   (select-window (event-window event))
   (let ((menu (Info-construct-menu event)))
-    (setq menu (nconc (list "Info" ; title: not shown
-			    "Info Commands:" "----")
+    (setq menu (nconc (list "Info" ; title: not displayed
+			    "     Info Commands"
+			    "--:shadowDoubleEtchedOut")
 		      menu))
     (let ((popup-menu-titles nil))
       (popup-menu menu))))
@@ -2469,14 +2683,14 @@
 		 Info-exit
 		 t
 		 "Exit info"]
+		[info::toolbar-next-icon
+		 Info-next
+		 t
+		 "Next entry in same section"]
 		[info::toolbar-prev-icon
 		 Info-prev
 		 t
 		 "Prev entry in same section"]
-		[info::toolbar-next-icon
-		 Info-next
-		 t
-		 "Next entry in same section"]
 		[info::toolbar-up-icon
 		 Info-up
 		 t