;;; info.el --- info package for Emacs
-;; Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001
+;; Copyright (C) 1985, 86, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Maintainer: FSF
The Lisp code is executed when the node is selected.")
(put 'Info-enable-active-nodes 'risky-local-variable t)
-(defcustom Info-fontify t
- "*Non-nil enables highlighting and fonts in Info nodes."
- :type 'boolean
- :group 'info)
-
(defface info-node
'((((class color) (background light)) (:foreground "brown" :weight bold :slant italic))
(((class color) (background dark)) (:foreground "white" :weight bold :slant italic))
(defface info-menu-5
'((((class color)) (:foreground "red1"))
(t (:underline t)))
- "Face for the fifth and nineth `*' in an Info menu."
+ "Face for every third `*' in an Info menu."
:group 'info)
(defface info-xref
:group 'info)
(defcustom Info-fontify-maximum-menu-size 100000
- "*Maximum size of menu to fontify if `Info-fontify' is non-nil."
+ "*Maximum size of menu to fontify if `font-lock-mode' is non-nil."
:type 'integer
:group 'info)
(defcustom Info-use-header-line t
- "*Non-nil means to put the beginning-of-node links in an emacs header-line.
+ "*Non-nil means to put the beginning-of-node links in an Emacs header-line.
A header-line does not scroll with the rest of the buffer."
:type 'boolean
:group 'info)
(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
+If nil, meaning not yet initialized, Info uses the environment
variable INFOPATH to initialize it, or `Info-default-directory-list'
if there is no INFOPATH variable in the environment.
:type 'boolean
:group 'info)
+(defcustom Info-mode-hook '(turn-on-font-lock)
+ "Hooks run when `info-mode' is called."
+ :type 'hook
+ :group 'info)
+
(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.
(pop-to-buffer "*info*")
(Info-directory))))
+;;;###autoload
+(defun info-emacs-manual ()
+ (interactive)
+ (info "emacs"))
+
;;;###autoload
(defun info-standalone ()
"Run Emacs as a standalone Info reader.
(beginning-of-line)
(when (re-search-forward regexp nil t)
(list (string-equal "Ref:" (match-string 1))
- (1+ (read (current-buffer)))
+ (+ (point-min) (read (current-buffer)))
major-mode)))))
(defun Info-find-in-tag-table (marker regexp)
(insert Info-dir-contents)
(goto-char (point-min)))
(let ((dirs (if Info-additional-directory-list
- (append Info-directory-list
- Info-additional-directory-list)
- Info-directory-list))
+ (append Info-directory-list
+ Info-additional-directory-list)
+ 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.
thisfilepos thisfilename)
(search-forward ": ")
(setq thisfilename (buffer-substring beg (- (point) 2)))
- (setq thisfilepos (read (current-buffer)))
+ (setq thisfilepos (+ (point-min) (read (current-buffer))))
;; read in version 19 stops at the end of number.
;; Advance to the next line.
(forward-line 1)
(defvar Info-header-line nil
"If the info node header is hidden, the text of the header.")
+(put 'Info-header-line 'risky-local-variable t)
(defun Info-select-node ()
"Select the info node that point is in.
(read (current-buffer))))))
(point-max)))
(if Info-enable-active-nodes (eval active-expression))
- (if Info-fontify (Info-fontify-node))
+ (Info-fontify-node)
(if Info-use-header-line
- (Info-setup-header-line)
+ (progn
+ (setq Info-header-line
+ (get-text-property (point-min) 'header-line))
+ (setq header-line-format 'Info-header-line)
+;;; It is useful to be able to copy the links line out of the buffer
+;;; with M-w.
+;;; (narrow-to-region (1+ header-end) (point-max))
+ )
(setq Info-header-line nil)
(setq header-line-format nil)) ; so the header line isn't displayed
(run-hooks 'Info-selection-hook)))))
") "
(or Info-current-node ""))))))
\f
-;; Skip the node header and make it into a header-line. This function
-;; should be called when the node is already narrowed.
-(defun Info-setup-header-line ()
- (goto-char (point-min))
- (let* ((case-fold-search t)
- (header-end (save-excursion (forward-line 1) (1- (point))))
- ;; If we find neither Next: nor Prev: link, show the entire
- ;; node header. Otherwise, don't show the File: and Node:
- ;; parts, to avoid wasting precious space on information that
- ;; is available in the mode line.
- (header-beg (if (re-search-forward
- "\\(next\\|prev[ious]*\\): "
- header-end t)
- (match-beginning 1)
- (point))))
- (set (make-local-variable 'Info-header-line)
- (buffer-substring header-beg header-end))
- (setq header-line-format 'Info-header-line)
- (narrow-to-region (1+ header-end) (point-max))))
-\f
;; Go to an info node specified with a filename-and-nodename string
;; of the sort that is found in pointers in nodes.
;; It does completion using the alist in Info-read-node-completion-table
;; unless STRING starts with an open-paren.
(defun Info-read-node-name-1 (string predicate code)
- (let ((no-completion (and (> (length string) 0) (eq (aref string 0) ?\())))
- (cond ((eq code nil)
- (if no-completion
- string
- (try-completion string Info-read-node-completion-table predicate)))
- ((eq code t)
- (if no-completion
- nil
- (all-completions string Info-read-node-completion-table predicate)))
- ((eq code 'lambda)
- (if no-completion
- t
- (assoc string Info-read-node-completion-table))))))
+ (cond
+ ;; First complete embedded file names.
+ ((string-match "\\`([^)]*\\'" string)
+ (let ((file (substring string 1)))
+ (cond
+ ((eq code nil)
+ (let ((comp (try-completion file 'locate-file-completion
+ (cons Info-directory-list
+ (mapcar 'car Info-suffix-list)))))
+ (cond
+ ((eq comp t) (concat string ")"))
+ (comp (concat "(" comp)))))
+ ((eq code t) (all-completions file 'locate-file-completion
+ (cons Info-directory-list
+ (mapcar 'car Info-suffix-list))))
+ (t nil))))
+ ;; If a file name was given, then any node is fair game.
+ ((string-match "\\`(" string)
+ (cond
+ ((eq code nil) string)
+ ((eq code t) nil)
+ (t t)))
+ ;; Otherwise use Info-read-node-completion-table.
+ ((eq code nil)
+ (try-completion string Info-read-node-completion-table predicate))
+ ((eq code t)
+ (all-completions string Info-read-node-completion-table predicate))
+ (t
+ (test-completion string Info-read-node-completion-table predicate))))
(defun Info-read-node-name (prompt &optional default)
(let* ((completion-ignore-case t)
(progn (search-forward "\n\^_")
(1- (point))))
(goto-char (point-min))
+ ;; Find the subfile we just searched.
(search-forward (concat "\n" osubfile ": "))
- (beginning-of-line)
+ ;; Skip that one.
+ (forward-line 1)
+ ;; Make a list of all following subfiles.
+ ;; Each elt has the form (VIRT-POSITION . SUBFILENAME).
(while (not (eobp))
(re-search-forward "\\(^.*\\): [0-9]+$")
(goto-char (+ (match-end 1) 2))
- (setq list (cons (cons (read (current-buffer))
+ (setq list (cons (cons (+ (point-min)
+ (read (current-buffer)))
(match-string-no-properties 1))
list))
(goto-char (1+ (match-end 0))))
- (setq list (nreverse list)
- current (car (car list))
- list (cdr list))))
+ ;; Put in forward order
+ (setq list (nreverse list))))
(while list
(message "Searching subfile %s..." (cdr (car list)))
(Info-read-subfile (car (car list)))
(save-excursion
(save-restriction
(goto-char (point-min))
- (when Info-header-line
- ;; expose the header line in the buffer
- (widen)
- (forward-line -1))
+;;; (when Info-header-line
+;;; ;; expose the header line in the buffer
+;;; (widen)
+;;; (forward-line -1))
(let ((bound (point)))
(forward-line 1)
(cond ((re-search-backward (concat name ":") bound t)
(while
(progn
(while (re-search-forward pattern nil t)
- (push (cons (match-string-no-properties 1)
- (match-beginning 1))
+ (push (match-string-no-properties 1)
completions))
;; Check subsequent nodes if applicable.
(and Info-complete-next-re
(list
(let ((Info-complete-menu-buffer (clone-buffer))
(Info-complete-next-re "\\<Index\\>"))
+ (if (equal Info-current-file "dir")
+ (error "The Info directory node has no index; use m to select a manual"))
(unwind-protect
(with-current-buffer Info-complete-menu-buffer
(Info-goto-index)
(completing-read "Index topic: " 'Info-complete-menu-item))
(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"))
(let ((orignode Info-current-node)
(rnode nil)
(pattern (format "\n\\* +\\([^\n:]*%s[^\n:]*\\):[ \t]*\\([^.\n]*\\)\\.[ \t]*\\([0-9]*\\)"
(if (or (re-search-forward (format
"[a-zA-Z]+: %s\\( \\|$\\)"
(regexp-quote name)) nil t)
+ ;; Find a function definition with a return type.
+ (re-search-forward (format
+ "[a-zA-Z]+: [a-zA-Z0-9_ *&]+ %s\\( \\|$\\)"
+ (regexp-quote name)) nil t)
(search-forward (format "`%s'" name) nil t)
(and (string-match "\\`.*\\( (.*)\\)\\'" name)
(search-forward
(define-key Info-mode-map "<" 'Info-top-node)
(define-key Info-mode-map ">" 'Info-final-node)
(define-key Info-mode-map "b" 'beginning-of-buffer)
+ (define-key Info-mode-map "c" 'Info-copy-current-node-name)
(define-key Info-mode-map "d" 'Info-directory)
(define-key Info-mode-map "e" 'Info-edit)
(define-key Info-mode-map "f" 'Info-follow-reference)
(defvar info-tool-bar-map
(if (display-graphic-p)
- (let ((tool-bar-map (make-sparse-keymap)))
- (tool-bar-add-item-from-menu 'Info-exit "close" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-prev "left_arrow" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-next "right_arrow" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-up "up_arrow" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-last "undo" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-top-node "home" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-index "index" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-goto-node "jump_to" Info-mode-map)
- (tool-bar-add-item-from-menu 'Info-search "search" Info-mode-map)
- tool-bar-map)))
+ (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-prev "left_arrow" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-next "right_arrow" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-up "up_arrow" map Info-mode-map)
+ (tool-bar-local-item-from-menu 'Info-last "undo" 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-index "index" 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-search "search" map Info-mode-map)
+ map)))
(defvar Info-menu-last-node nil)
;; Last node the menu was created for.
(setq Info-tag-table-buffer nil)
(make-local-variable 'Info-history)
(make-local-variable 'Info-index-alternatives)
+ (make-local-variable 'Info-header-line)
(set (make-local-variable 'tool-bar-map) info-tool-bar-map)
;; 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 'clone-buffer-hook 'Info-clone-buffer-hook nil t)
+ (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
(Info-set-mode-line)
(run-hooks 'Info-mode-hook))
(goto-char (point-min))
(when (re-search-forward "\\* Menu:" nil t)
(put-text-property (match-beginning 0) (match-end 0)
- 'face 'info-menu-header)
+ 'font-lock-face 'info-menu-header)
(while (re-search-forward "\n\n\\([^*\n ].*\\)\n\n?[*]" nil t)
(put-text-property (match-beginning 1) (match-end 1)
- 'face 'info-menu-header)))))
+ 'font-lock-face 'info-menu-header)))))
+
+(defvar Info-next-link-keymap
+ (let ((keymap (make-sparse-keymap)))
+ (define-key keymap [header-line mouse-1] 'Info-next)
+ (define-key keymap [header-line mouse-2] 'Info-next)
+ (define-key keymap [header-line down-mouse-1] 'ignore)
+ (define-key keymap [mouse-2] 'Info-next)
+ keymap)
+ "Keymap to put on the Next link in the text or the header line.")
+
+(defvar Info-prev-link-keymap
+ (let ((keymap (make-sparse-keymap)))
+ (define-key keymap [header-line mouse-1] 'Info-prev)
+ (define-key keymap [header-line mouse-2] 'Info-prev)
+ (define-key keymap [header-line down-mouse-1] 'ignore)
+ (define-key keymap [mouse-2] 'Info-prev)
+ keymap)
+ "Keymap to put on the Prev link in the text or the header line.")
+
+
+(defvar Info-up-link-keymap
+ (let ((keymap (make-sparse-keymap)))
+ (define-key keymap [header-line mouse-1] 'Info-up)
+ (define-key keymap [header-line mouse-2] 'Info-up)
+ (define-key keymap [header-line down-mouse-1] 'ignore)
+ (define-key keymap [mouse-2] 'Info-up)
+ keymap)
+ "Keymap to put on the Up link in the text or the header line.")
(defun Info-fontify-node ()
;; Only fontify the node if it hasn't already been done. [We pass in
;; LIMIT arg to `next-property-change' because it seems to search past
;; (point-max).]
- (unless (and (< (next-property-change (point-min) nil (point-max))
- (point-max))
- ;; But do put the text properties if the local-map property
- ;; is inconsistent with Info-use-header-line's value.
- (eq
- (= (next-single-property-change
- (point-min) 'local-map nil (point-max))
- (point-max))
- (null Info-use-header-line)))
+ (unless (< (next-property-change (point-min) nil (point-max))
+ (point-max))
(save-excursion
(let ((buffer-read-only nil)
(case-fold-search t))
(tbeg (match-beginning 1))
(tag (buffer-substring tbeg (match-end 1))))
(if (string-equal tag "Node")
- (put-text-property nbeg nend 'face 'info-header-node)
- (put-text-property nbeg nend 'face 'info-header-xref)
- (put-text-property nbeg nend 'mouse-face 'highlight)
+ (put-text-property nbeg nend 'font-lock-face 'info-header-node)
+ (put-text-property nbeg nend 'font-lock-face 'info-header-xref)
+ (put-text-property tbeg nend 'mouse-face 'highlight)
(put-text-property tbeg nend
'help-echo
(concat "Go to node "
(buffer-substring nbeg nend)))
- ;; Don't bind mouse events on the header line if we
- ;; aren't going to display the header line.
- (when Info-use-header-line
- (let ((fun (cdr (assoc tag '(("Prev" . Info-prev)
- ("Next" . Info-next)
- ("Up" . Info-up))))))
- (when fun
- (let ((keymap (make-sparse-keymap)))
- (define-key keymap [header-line down-mouse-1] fun)
- (define-key keymap [header-line down-mouse-2] fun)
- (put-text-property tbeg nend 'local-map keymap)))))
- (if (not Info-use-header-line)
- ;; In case they switched Info-use-header-line off
- ;; in the middle of an Info session, some text
- ;; properties may have been left lying around from
- ;; past visits of this node. Remove them.
- (remove-text-properties tbeg nend '(local-map nil)))
- ))))
+ ;; Always set up the text property keymap.
+ ;; It will either be used in the buffer
+ ;; or copied in the header line.
+ (cond ((equal tag "Prev")
+ (put-text-property tbeg nend 'keymap
+ Info-prev-link-keymap))
+ ((equal tag "Next")
+ (put-text-property tbeg nend 'keymap
+ Info-next-link-keymap))
+ ((equal tag "Up")
+ (put-text-property tbeg nend 'keymap
+ Info-up-link-keymap))))))
+ (goto-char (point-min))
+ (let ((header-end (save-excursion (end-of-line) (point)))
+ header)
+ ;; If we find neither Next: nor Prev: link, show the entire
+ ;; node header. Otherwise, don't show the File: and Node:
+ ;; parts, to avoid wasting precious space on information that
+ ;; is available in the mode line.
+ (if (re-search-forward
+ "\\(next\\|up\\|prev[ious]*\\): "
+ header-end t)
+ (progn
+ (goto-char (match-beginning 1))
+ (setq header (buffer-substring (point) header-end)))
+ (if (re-search-forward "node:[ \t]*[^ \t]+[ \t]*" nil t)
+ (setq header
+ (concat "No next, prev or up links -- "
+ (buffer-substring (point) header-end)))
+ (setq header (buffer-substring (point) header-end))))
+
+ (put-text-property (point-min) (1+ (point-min))
+ 'header-line header)
+ ;; Hide the part of the first line
+ ;; that is in the header, if it is just part.
+ (unless (bobp)
+ ;; Hide the punctuation at the end, too.
+ (skip-chars-backward " \t,")
+ (put-text-property (point) header-end 'invisible t))))
(goto-char (point-min))
(while (re-search-forward "\n\\([^ \t\n].+\\)\n\\(\\*+\\|=+\\|-+\\|\\.+\\)$"
nil t)
- (let ((c (preceding-char))
- face)
- (cond ((= c ?*) (setq face 'Info-title-1-face))
- ((= c ?=) (setq face 'Info-title-2-face))
- ((= c ?-) (setq face 'Info-title-3-face))
- (t (setq face 'Info-title-4-face)))
+ (let* ((c (preceding-char))
+ (face
+ (cond ((= c ?*) 'Info-title-1-face)
+ ((= c ?=) 'Info-title-2-face)
+ ((= c ?-) 'Info-title-3-face)
+ (t 'Info-title-4-face))))
(put-text-property (match-beginning 1) (match-end 1)
- 'face face))
+ 'font-lock-face face))
;; This is a serious problem for trying to handle multiple
;; frame types at once. We want this text to be invisible
;; on frames that can display the font above.
(if (= (char-after (1- (match-beginning 0))) ?\") ; hack
nil
(add-text-properties (match-beginning 1) (match-end 1)
- '(face info-xref
+ '(font-lock-face info-xref
mouse-face highlight
help-echo "mouse-2: go to this node"))))
(goto-char (point-min))
(if (zerop (% n 3)) ; visual aids to help with 1-9 keys
(put-text-property (match-beginning 0)
(1+ (match-beginning 0))
- 'face 'info-menu-5))
+ 'font-lock-face 'info-menu-5))
(add-text-properties (match-beginning 1) (match-end 1)
- '(face info-xref
+ '(font-lock-face info-xref
mouse-face highlight
help-echo "mouse-2: go to this node")))))
(Info-fontify-menu-headers)