(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".
This commit is contained in:
Richard M. Stallman 1993-08-02 04:22:12 +00:00
parent 04402ae3dc
commit 552775bd93

View file

@ -47,6 +47,9 @@ The Lisp code is executed when the node is selected.")
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 @@ or nil if current info file is not split into subfiles.")
"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 @@ to read a file name from the minibuffer."
(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 @@ to read a file name from the minibuffer."
(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 @@ to read a file name from the minibuffer."
(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 @@ to read a file name from the minibuffer."
(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 @@ to read a file name from the minibuffer."
(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 @@ N is the digit argument used to invoke this command."
(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 @@ N is the digit argument used to invoke this command."
(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 @@ N is the digit argument used to invoke this command."
(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 @@ Give a blank topic name to go to the Index node itself."
(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 @@ At end of the node's text, moves to the next node."
(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 @@ Advanced commands:
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 @@ Advanced commands:
(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 @@ Interactively, if the binding is execute-extended-command, a command is read."
(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)