changeset 4410:25fb71fc2643

(Info-fontify-node): New function. (Info-fontify): New variable. (Info-mode): Initialize Info-related faces. (Info-select-node): Fontify the node if necessary. (Info-goto-node): Provide completion for node names. (Info-read-node-name, Info-build-node-completions): New functions. (Info-current-file-completions): New variable. (Info-find-node): Clear completions cache. (Info-next-reference, Info-prev-reference): New commands. (Info-mode-map): Bind these to TAB and M-TAB. (Info-next-preorder): Special case if sitting on "*Note" reference. (Info-standalone): New variable. (Info-exit): Exit Emacs if in standalone mode. (info-standalone): New function. (Info-summary): Added `bury-buffer' call. (Info-no-error): Renamed from `no-error'. (Info-suffix-list): Put ".info" before "" to deal with directory named "foo" next to file "foo.info".
author Richard M. Stallman <rms@gnu.org>
date Mon, 02 Aug 1993 04:22:12 +0000
parents 084df29978c7
children cde0e3c3b642
files lisp/info.el
diffstat 1 files changed, 169 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/info.el	Sun Aug 01 23:03:26 1993 +0000
+++ b/lisp/info.el	Mon Aug 02 04:22:12 1993 +0000
@@ -47,6 +47,9 @@
 This value is used as the default for `Info-directory-list'.  It is set
 in paths.el.")
 
+(defvar Info-fontify t
+  "*Non-nil enables highlighting and fonts in Info nodes.")
+
 (defvar Info-directory-list
   (let ((path (getenv "INFOPATH")))
     (if path
@@ -78,11 +81,17 @@
   "Marker pointing at beginning of current Info file's tag table.
 Marker points nowhere if file has no tag table.")
 
+(defvar Info-current-file-completions nil
+  "Cached completion list for current Info file.")
+
 (defvar Info-index-alternatives nil
   "List of possible matches for last Info-index command.")
 
-(defvar Info-suffix-list '( (""         . nil)
-			    (".info"    . nil)
+(defvar Info-standalone nil
+  "Non-nil if Emacs was started solely as an Info browser.")
+
+(defvar Info-suffix-list '( (".info"    . nil)
+			    (""         . nil)
 			    (".Z"       . "uncompress")
 			    (".Y"       . "unyabba")
 			    (".gz"      . "gunzip")
@@ -131,6 +140,24 @@
 	(switch-to-buffer "*info*")
       (Info-directory))))
 
+;;;###autoload
+(defun info-standalone ()
+  "Run Emacs as a standalone Info reader.
+Usage:  emacs -f info-standalone [filename]
+In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
+  (setq Info-standalone t)
+  (if (and command-line-args-left
+	   (not (string-match "^-" (car command-line-args-left))))
+      (condition-case err
+	  (progn
+	    (info (car command-line-args-left))
+	    (setq command-line-args-left (cdr command-line-args-left)))
+	(error (send-string-to-terminal
+		(format "%s\n" (if (eq (car-safe err) 'error)
+				   (nth 1 err) err)))
+	       (save-buffers-kill-emacs)))
+    (info)))
+
 ;; 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.
@@ -190,6 +217,7 @@
 	    (let ((buffer-read-only nil))
 	      (setq Info-current-file nil
 		    Info-current-subfile nil
+		    Info-current-file-completions nil
 		    Info-index-alternatives nil
 		    buffer-file-name nil)
 	      (erase-buffer)
@@ -476,6 +504,7 @@
 					(read (current-buffer))))))
 			 (point-max)))
      (if Info-enable-active-nodes (eval active-expression))
+     (if Info-fontify (Info-fontify-node))
      (run-hooks 'Info-selection-hook))))
 
 (defun Info-set-mode-line ()
@@ -493,7 +522,7 @@
 
 (defun Info-goto-node (nodename)
   "Go to info node named NAME.  Give just NODENAME or (FILENAME)NODENAME."
-  (interactive "sGoto node: ")
+  (interactive (list (Info-read-node-name "Goto node: ")))
   (let (filename)
     (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
 		  nodename)
@@ -507,6 +536,42 @@
       (if trim (setq nodename (substring nodename 0 trim))))
     (Info-find-node (if (equal filename "") nil filename)
 		    (if (equal nodename "") "Top" nodename))))
+
+(defun Info-read-node-name (prompt &optional default)
+  (let* ((completion-ignore-case t)
+	 (nodename (completing-read prompt (Info-build-node-completions))))
+    (if (equal nodename "")
+	(or default
+	    (Info-read-node-name prompt))
+      nodename)))
+
+(defun Info-build-node-completions ()
+  (or Info-current-file-completions
+      (let ((compl nil))
+	(save-excursion
+	  (save-restriction
+	    (if (marker-buffer Info-tag-table-marker)
+		(progn
+		  (set-buffer (marker-buffer Info-tag-table-marker))
+		  (goto-char Info-tag-table-marker)
+		  (while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
+		    (setq compl
+			  (cons (list (buffer-substring (match-beginning 1)
+							(match-end 1)))
+				compl))))
+	      (widen)
+	      (goto-char (point-min))
+	      (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)
+		      (setq compl 
+			    (cons (list (buffer-substring (match-beginning 1)
+							  (match-end 1)))
+				  compl))))))))
+	(setq Info-current-file-completions compl))))
 
 (defun Info-restore-point (hl)
   "If this node has been visited, restore the point value when we left."
@@ -879,8 +944,10 @@
 (defun Info-exit ()
   "Exit Info by selecting some other buffer."
   (interactive)
-  (switch-to-buffer (prog1 (other-buffer (current-buffer))
-			   (bury-buffer (current-buffer)))))
+  (if Info-standalone
+      (save-buffers-kill-emacs)
+    (switch-to-buffer (prog1 (other-buffer (current-buffer))
+			(bury-buffer (current-buffer))))))
 
 (defun Info-next-menu-item ()
   (interactive)
@@ -900,21 +967,24 @@
 	(error "No previous items in menu"))
     (Info-goto-node (Info-extract-menu-node-name))))
 
-(defmacro no-error (&rest body)
+(defmacro Info-no-error (&rest body)
   (list 'condition-case nil (cons 'progn (append body '(t))) '(error nil)))
 
 (defun Info-next-preorder ()
   "Go to the next node, popping up a level if there is none."
   (interactive)
-  (cond ((no-error (Info-next-menu-item))	)
-	((no-error (Info-up)) 			(forward-line 1))
+  (cond ((looking-at "\\*note[ \n]*\\([^:]*\\):")
+	 (Info-follow-reference
+	  (buffer-substring (match-beginning 1) (match-end 1))))
+	((Info-no-error (Info-next-menu-item))	)
+	((Info-no-error (Info-up))		(forward-line 1))
 	(t 					(error "No more nodes"))))
 
 (defun Info-last-preorder ()
   "Go to the last node, popping up a level if there is none."
   (interactive)
-  (cond ((no-error (Info-last-menu-item))	)
-	((no-error (Info-up)) 			(forward-line -1))
+  (cond ((Info-no-error (Info-last-menu-item))	)
+	((Info-no-error (Info-up))		(forward-line -1))
 	(t 					(error "No previous nodes"))))
 
 (defun Info-scroll-up ()
@@ -933,6 +1003,39 @@
       (scroll-down))
   )
 
+(defun Info-next-reference ()
+  "Move cursor to the next cross-reference or menu item in the node."
+  (interactive)
+  (let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
+	(old-pt (point)))
+    (or (eobp) (forward-char 1))
+    (or (re-search-forward pat nil t)
+	(progn
+	  (goto-char (point-min))
+	  (or (re-search-forward pat nil t)
+	      (progn
+		(goto-char old-pt)
+		(error "No cross references in this node")))))
+    (goto-char (match-beginning 0))
+    (if (looking-at "\\* Menu:")
+	(Info-next-reference))))
+
+(defun Info-prev-reference ()
+  "Move cursor to the previous cross-reference or menu item in the node."
+  (interactive)
+  (let ((pat "\\*note[ \n\t]*\\([^:]*\\):\\|^\\* .*:")
+	(old-pt (point)))
+    (or (re-search-backward pat nil t)
+	(progn
+	  (goto-char (point-max))
+	  (or (re-search-backward pat nil t)
+	      (progn
+		(goto-char old-pt)
+		(error "No cross references in this node")))))
+    (goto-char (match-beginning 0))
+    (if (looking-at "\\* Menu:")
+	(Info-prev-reference))))
+
 (defun Info-index (topic)
   "Look up a string in the index for this file.
 The index is defined as the first node in the top-level menu whose
@@ -1054,7 +1157,8 @@
 		    (if (not (eq ?\  (setq ch (read-event))))
 			(progn (setq unread-command-events (list ch)) nil)
 		      flag))
-	(scroll-up)))))
+	(scroll-up)))
+    (bury-buffer "*Help*")))
 
 (defun Info-get-token (pos start all &optional errorstring)
   "Return the token around POS,
@@ -1126,6 +1230,8 @@
   (define-key Info-mode-map "." 'beginning-of-buffer)
   (define-key Info-mode-map " " 'Info-scroll-up)
   (define-key Info-mode-map "\C-m" 'Info-next-preorder)
+  (define-key Info-mode-map "\t" 'Info-next-reference)
+  (define-key Info-mode-map "\e\t" 'Info-prev-reference)
   (define-key Info-mode-map "1" 'Info-nth-menu-item)
   (define-key Info-mode-map "2" 'Info-nth-menu-item)
   (define-key Info-mode-map "3" 'Info-nth-menu-item)
@@ -1199,11 +1305,14 @@
 2, 3, 4, 5   Pick second ... fifth item in node's menu.
 \\[Info-goto-node]	Move to node specified by name.
 	You may include a filename as well, as (FILENAME)NODENAME.
+\\[universal-argument] \\[info]	Move to new Info file with completion.
 \\[Info-search]	Search through this Info file for specified regexp,
 	and select the node in which the next occurrence is found.
 \\[Info-next-preorder]	Next-preorder; that is, try to go to the next menu item,
 	and if that fails try to move up, and if that fails, tell user
- 	he/she is done reading."
+ 	he/she is done reading.
+\\[Info-next-reference]	Move cursor to next cross-reference or menu item.
+\\[Info-prev-reference]	Move cursor to previous cross-reference or menu item."
   (kill-all-local-variables)
   (setq major-mode 'Info-mode)
   (setq mode-name "Info")
@@ -1218,6 +1327,20 @@
   (make-local-variable 'Info-tag-table-marker)
   (make-local-variable 'Info-history)
   (make-local-variable 'Info-index-alternatives)
+  (if (fboundp 'make-face)
+      (progn
+	(make-face 'info-node)
+	(make-face 'info-menu-5)
+	(make-face 'info-xref)
+	(or (face-differs-from-default-p 'info-node)
+	    (if (face-differs-from-default-p 'bold-italic)
+		(copy-face 'bold-italic 'info-node)
+	      (copy-face 'bold 'info-node)))
+	(or (face-differs-from-default-p 'info-menu-5)
+	    (set-face-underline-p 'info-menu-5 t))
+	(or (face-differs-from-default-p 'info-xref)
+	    (copy-face 'bold 'info-xref)))
+    (setq Info-fontify nil))
   (Info-set-mode-line)
   (run-hooks 'Info-mode-hook))
 
@@ -1336,6 +1459,40 @@
 	    (read-command "Find documentation for command: ")))
 	  (t
 	   (Info-goto-emacs-command-node command)))))
+
+(defun Info-fontify-node ()
+  (save-excursion
+    (let ((buffer-read-only nil))
+      (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]+\\),?")
+	      (goto-char (match-end 0))
+	      (put-text-property (match-beginning 1) (match-end 1)
+				 'face 'info-xref))))
+      (goto-char (point-min))
+      (while (re-search-forward "\\*Note[ \n\t]*\\([^:]*\\):" nil t)
+	(if (= (char-after (1- (match-beginning 0))) ?\") ; hack
+	    nil
+	  (put-text-property (match-beginning 1) (match-end 1)
+			     'face 'info-xref)))
+      (goto-char (point-min))
+      (if (and (search-forward "\n* Menu:" nil t)
+	       (not (string-match "\\<Index\\>" Info-current-node))
+	       ;; Don't take time to annotate huge menus
+	       (< (- (point-max) (point)) 10000))
+	  (let ((n 0))
+	    (while (re-search-forward "^\\* \\([^:\t\n]*\\):" nil t)
+	      (setq n (1+ n))
+	      (if (memq n '(5 9))   ; visual aids to help with 1-9 keys
+		  (put-text-property (match-beginning 0)
+				     (1+ (match-beginning 0))
+				     'face 'info-menu-5))
+	      (put-text-property (match-beginning 1) (match-end 1)
+				 'face 'info-node))))
+      (set-buffer-modified-p nil))))
 
 (provide 'info)