X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/de22f49c43050fa184cd0426e25db61c0c9a8d6e..68b77b6489e57a7a60a18a407af50042bab31dab:/lisp/info.el diff --git a/lisp/info.el b/lisp/info.el index 5d86d0cb46..84e8248e02 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -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 Free Software Foundation, Inc. +;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: help @@ -129,21 +129,14 @@ The Lisp code is executed when the node is selected.") (put 'info-menu-5 'face-alias 'info-menu-star) (defface info-xref - '((((min-colors 88) - (class color) (background light)) :foreground "blue1" :underline t) - (((class color) (background light)) :foreground "blue" :underline t) - (((min-colors 88) - (class color) (background dark)) :foreground "cyan1" :underline t) - (((class color) (background dark)) :foreground "cyan" :underline t) - (t :underline t)) - "Face for Info cross-references." + '((t :inherit link)) + "Face for unvisited Info cross-references." :group 'info) (defface info-xref-visited - '((default :inherit info-xref) - (((class color) (background light)) :foreground "magenta4") - (((class color) (background dark)) :foreground "violet")) + '((t :inherit (link-visited info-xref))) "Face for visited Info cross-references." + :version "22.1" :group 'info) (defcustom Info-fontify-visited-nodes t @@ -153,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) @@ -290,12 +284,11 @@ with wrapping around the current Info node." (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. -It doesn't contain directory names or file name extensions added by Info. -Can also be t when using `Info-on-current-buffer'.") +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.") @@ -310,6 +303,9 @@ Marker points nowhere if file has no tag table.") (defvar Info-current-file-completions nil "Cached completion list for current Info file.") +(defvar Info-file-supports-index-cookies nil + "Non-nil if current Info file supports index cookies.") + (defvar Info-index-alternatives nil "List of possible matches for last `Info-index' command.") @@ -446,8 +442,7 @@ Do the right thing if the file has been compressed or zipped." (or tail (error "Can't find %s or any compressed version of it" filename))) ;; check for conflict with jka-compr - (if (and (featurep 'jka-compr) - (jka-compr-installed-p) + (if (and (jka-compr-installed-p) (jka-compr-get-compression-info fullname)) (setq decoder nil)) (if decoder @@ -469,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)))))) @@ -520,22 +515,22 @@ Do the right thing if the file has been compressed or zipped." (Info-default-dirs))))))) ;;;###autoload -(defun info-other-window (&optional file) +(defun info-other-window (&optional file-or-node) "Like `info' but show the Info buffer in another window." (interactive (if current-prefix-arg (list (read-file-name "Info file name: " nil nil t)))) (let (same-window-buffer-names same-window-regexps) - (info file))) + (info file-or-node))) ;;;###autoload (add-hook 'same-window-regexps "\\*info\\*\\(\\|<[0-9]+>\\)") ;;;###autoload (put 'info 'info-file "emacs") ;;;###autoload -(defun info (&optional file buffer) +(defun info (&optional file-or-node buffer) "Enter Info, the documentation browser. -Optional argument FILE specifies the file to examine; +Optional argument FILE-OR-NODE specifies the file to examine; the default is the top-level directory of Info. -Called from a program, FILE may specify an Info node of the form +Called from a program, FILE-OR-NODE may specify an Info node of the form `(FILENAME)NODENAME'. Optional argument BUFFER specifies the Info buffer name; the default buffer name is *info*. If BUFFER exists, @@ -558,17 +553,19 @@ in all the directories in that path." (pop-to-buffer (or buffer "*info*")) (if (and buffer (not (eq major-mode 'Info-mode))) (Info-mode)) - (if file + (if file-or-node ;; If argument already contains parentheses, don't add another set ;; since the argument will then be parsed improperly. This also ;; has the added benefit of allowing node names to be included ;; following the parenthesized filename. (Info-goto-node - (if (and (stringp file) (string-match "(.*)" file)) - file - (concat "(" file ")"))) - (if (zerop (buffer-size)) - (Info-directory)))) + (if (and (stringp file-or-node) (string-match "(.*)" file-or-node)) + file-or-node + (concat "(" file-or-node ")"))) + (if (and (zerop (buffer-size)) + (null Info-history)) + ;; If we just created the Info buffer, go to the directory. + (Info-directory)))) ;;;###autoload (defun info-emacs-manual () @@ -626,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 `./' @@ -677,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. @@ -687,17 +679,19 @@ it says do not attempt further (recursive) error recovery." (setq filename (Info-find-file filename)) ;; Go into Info buffer. (or (eq major-mode 'Info-mode) (pop-to-buffer "*info*")) - ;; Record the node we are leaving. - (if (and Info-current-file (not no-going-back)) - (setq Info-history - (cons (list Info-current-file Info-current-node (point)) - Info-history))) + ;; Record the node we are leaving, if we were in one. + (and (not no-going-back) + Info-current-file + (setq Info-history + (cons (list Info-current-file Info-current-node (point)) + Info-history))) (Info-find-node-2 filename nodename no-going-back)) +;;;###autoload (defun Info-on-current-buffer (&optional nodename) - "Use the `Info-mode' to browse the current Info buffer. -If a prefix arg is provided, it queries for the NODENAME which -else defaults to \"Top\"." + "Use Info mode to browse the current Info buffer. +With a prefix arg, this queries for the node name to visit first; +otherwise, that defaults to `Top'." (interactive (list (if current-prefix-arg (completing-read "Node name: " (Info-build-node-completions) @@ -705,7 +699,10 @@ else defaults to \"Top\"." (unless nodename (setq nodename "Top")) (info-initialize) (Info-mode) - (set (make-local-variable 'Info-current-file) t) + (set (make-local-variable 'Info-current-file) + (or buffer-file-name + ;; If called on a non-file buffer, make a fake file name. + (concat default-directory (buffer-name)))) (Info-find-node-2 nil nodename)) ;; It's perhaps a bit nasty to kill the *info* buffer to force a re-read, @@ -723,8 +720,8 @@ is preserved, if possible." (pline (count-lines (point-min) (line-beginning-position))) (wline (count-lines (point-min) (window-start))) (old-history Info-history) - (new-history (and Info-current-file - (list Info-current-file Info-current-node (point))))) + (new-history (and Info-current-file + (list Info-current-file Info-current-node (point))))) (kill-buffer (current-buffer)) (Info-find-node filename nodename) (setq Info-history old-history) @@ -842,6 +839,19 @@ a case-insensitive match is tried." (info-insert-file-contents filename nil) (setq default-directory (file-name-directory filename)))) (set-buffer-modified-p nil) + + ;; Check makeinfo version for index cookie support + (let ((found nil)) + (goto-char (point-min)) + (condition-case () + (if (and (re-search-forward + "makeinfo[ \n]version[ \n]\\([0-9]+.[0-9]+\\)" + (line-beginning-position 3) t) + (not (version< (match-string 1) "4.7"))) + (setq found t)) + (error nil)) + (set (make-local-variable 'Info-file-supports-index-cookies) found)) + ;; See whether file has a tag table. Record the location if yes. (goto-char (point-max)) (forward-line -8) @@ -877,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. @@ -1190,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)) @@ -1201,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) @@ -1305,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]. @@ -1379,17 +1398,33 @@ any double quotes or backslashes must be escaped (\\\",\\\\)." (Info-hide-cookies-node) (run-hooks 'Info-selection-hook))))) +(defvar Info-mode-line-node-keymap + (let ((map (make-sparse-keymap))) + (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.") + (defun Info-set-mode-line () (setq mode-line-buffer-identification (nconc (propertized-buffer-identification "%b") (list - (concat " (" - (file-name-nondirectory - (if (stringp Info-current-file) - Info-current-file - (or buffer-file-name ""))) - ") " - (or Info-current-node "")))))) + (concat + " (" + (if (stringp Info-current-file) + (replace-regexp-in-string + "%" "%%" (file-name-nondirectory Info-current-file)) + (format "*%S*" Info-current-file)) + ") " + (if 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" + 'mouse-face 'mode-line-highlight + 'local-map Info-mode-line-node-keymap) + "")))))) ;; Go to an Info node specified with a filename-and-nodename string ;; of the sort that is found in pointers in nodes. @@ -1502,7 +1537,12 @@ PATH-AND-SUFFIXES is a pair of lists, (DIRECTORIES . SUFFIXES)." ;; Arrange to highlight the proper letters in the completion list buffer. (put 'Info-read-node-name-1 'completion-base-size-function - (lambda () 1)) + (lambda () + (if (string-match "\\`([^)]*\\'" + (or completion-common-substring + (minibuffer-completion-contents))) + 1 + 0))) (defun Info-read-node-name (prompt &optional default) (let* ((completion-ignore-case t) @@ -1521,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)) @@ -1613,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)) @@ -1632,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))) @@ -1701,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)) @@ -1796,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 () @@ -1818,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))))))))) @@ -1840,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." @@ -1868,13 +1918,14 @@ If SAME-FILE is non-nil, do not move to a different Info file." (let ((old-node Info-current-node) (old-file Info-current-file) (node (Info-extract-pointer "up")) p) - (and (or same-file (not (stringp Info-current-file))) + (and same-file (string-match "^(" node) (error "Up node is in another 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) ")") @@ -1942,49 +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 ": (" (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." @@ -2184,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) @@ -2238,7 +2295,8 @@ Because of ambiguities, this should be concatenated with something like (let ((pattern (concat "\n\\* +\\(" (regexp-quote string) Info-menu-entry-name-re "\\):" Info-node-spec-re)) - completions) + completions + (complete-nodes Info-complete-nodes)) ;; Check the cache. (if (and (equal (nth 0 Info-complete-cache) Info-current-file) (equal (nth 1 Info-complete-cache) Info-current-node) @@ -2259,9 +2317,9 @@ Because of ambiguities, this should be concatenated with something like (or (and Info-complete-next-re (setq nextnode (Info-extract-pointer "next" t)) (string-match Info-complete-next-re nextnode)) - (and Info-complete-nodes - (setq Info-complete-nodes (cdr Info-complete-nodes) - nextnode (car Info-complete-nodes))))) + (and complete-nodes + (setq complete-nodes (cdr complete-nodes) + nextnode (car complete-nodes))))) (Info-goto-node nextnode)) ;; Go back to the start node (for the next completion). (unless (equal Info-current-node orignode) @@ -2562,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' @@ -2588,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) @@ -2646,65 +2722,66 @@ 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)) - ;; Find nodes with index cookie - (let* ((default-directory (or (and (stringp file) - (file-name-directory - (setq file (Info-find-file file)))) - default-directory)) - Info-history Info-history-list Info-fontify-maximum-menu-size - (main-file file) subfiles nodes node) - (condition-case nil - (with-temp-buffer - (while (or main-file subfiles) - (erase-buffer) - (info-insert-file-contents (or main-file (car subfiles))) - (goto-char (point-min)) - (while (search-forward "\0\b[index\0\b]" nil 'move) - (save-excursion - (re-search-backward "^\^_") - (search-forward "Node: ") - (setq nodes (cons (Info-following-node-name) nodes)))) - (if main-file - (save-excursion - (goto-char (point-min)) - (if (search-forward "\n\^_\nIndirect:" nil t) - (let ((bound (save-excursion (search-forward "\n\^_" nil t)))) - (while (re-search-forward "^\\(.*\\): [0-9]+$" bound t) - (setq subfiles (cons (match-string-no-properties 1) - subfiles))))) - (setq subfiles (nreverse subfiles) - main-file nil)) - (setq subfiles (cdr subfiles))))) - (error nil)) - (if nodes - (setq nodes (nreverse nodes) - Info-index-nodes (cons (cons file nodes) Info-index-nodes))) - nodes) - ;; Find nodes with the word "Index" in the node name - (let ((case-fold-search t) - Info-history Info-history-list Info-fontify-maximum-menu-size - nodes node) - (condition-case nil - (with-temp-buffer - (Info-mode) - (Info-find-node file "Top") - (when (and (search-forward "\n* menu:" nil t) - (re-search-forward "\n\\* \\(.*\\\\)" nil t)) - (goto-char (match-beginning 1)) - (setq nodes (list (Info-extract-menu-node-name))) - (Info-goto-node (car nodes)) - (while (and (setq node (Info-extract-pointer "next" t)) - (string-match "\\" node)) - (setq nodes (cons node nodes)) - (Info-goto-node node)))) - (error nil)) - (if nodes - (setq nodes (nreverse nodes) - Info-index-nodes (cons (cons file nodes) Info-index-nodes))) - nodes) + (if Info-file-supports-index-cookies + ;; Find nodes with index cookie + (let* ((default-directory (or (and (stringp file) + (file-name-directory + (setq file (Info-find-file file)))) + default-directory)) + Info-history Info-history-list Info-fontify-maximum-menu-size + (main-file file) subfiles nodes node) + (condition-case nil + (with-temp-buffer + (while (or main-file subfiles) + (erase-buffer) + (info-insert-file-contents (or main-file (car subfiles))) + (goto-char (point-min)) + (while (search-forward "\0\b[index\0\b]" nil 'move) + (save-excursion + (re-search-backward "^\^_") + (search-forward "Node: ") + (setq nodes (cons (Info-following-node-name) nodes)))) + (if main-file + (save-excursion + (goto-char (point-min)) + (if (search-forward "\n\^_\nIndirect:" nil t) + (let ((bound (save-excursion (search-forward "\n\^_" nil t)))) + (while (re-search-forward "^\\(.*\\): [0-9]+$" bound t) + (setq subfiles (cons (match-string-no-properties 1) + subfiles))))) + (setq subfiles (nreverse subfiles) + main-file nil)) + (setq subfiles (cdr subfiles))))) + (error nil)) + (if nodes + (setq nodes (nreverse nodes) + Info-index-nodes (cons (cons file nodes) Info-index-nodes))) + nodes) + ;; Else find nodes with the word "Index" in the node name + (let ((case-fold-search t) + Info-history Info-history-list Info-fontify-maximum-menu-size + nodes node) + (condition-case nil + (with-temp-buffer + (Info-mode) + (Info-find-node file "Top") + (when (and (search-forward "\n* menu:" nil t) + (re-search-forward "\n\\* \\(.*\\\\)" nil t)) + (goto-char (match-beginning 1)) + (setq nodes (list (Info-extract-menu-node-name))) + (Info-goto-node (car nodes)) + (while (and (setq node (Info-extract-pointer "next" t)) + (string-match "\\" node)) + (setq nodes (cons node nodes)) + (Info-goto-node node)))) + (error nil)) + (if nodes + (setq nodes (nreverse nodes) + Info-index-nodes (cons (cons file nodes) Info-index-nodes))) + nodes)) ;; If file has no index nodes, still add it to the cache (setq Info-index-nodes (cons (cons file nil) Info-index-nodes))) (cdr (assoc file Info-index-nodes))) @@ -2718,17 +2795,17 @@ If FILE is nil, check the current Info file." (member (or node Info-current-node) (Info-index-nodes file)) ;; Don't search all index nodes if request is only for the current node ;; and file is not in the cache of index nodes - (or - (save-match-data - (string-match "\\" (or node Info-current-node ""))) - (save-excursion - (goto-char (+ (or (save-excursion - (search-backward "\n\^_" nil t)) - (point-min)) 2)) - (search-forward "\0\b[index\0\b]" - (or (save-excursion - (search-forward "\n\^_" nil t)) - (point-max)) t))))) + (if Info-file-supports-index-cookies + (save-excursion + (goto-char (+ (or (save-excursion + (search-backward "\n\^_" nil t)) + (point-min)) 2)) + (search-forward "\0\b[index\0\b]" + (or (save-excursion + (search-forward "\n\^_" nil t)) + (point-max)) t)) + (save-match-data + (string-match "\\" (or node Info-current-node "")))))) (defun Info-goto-index () "Go to the first index node." @@ -2738,14 +2815,15 @@ If FILE is nil, check the current Info file." ;;;###autoload (defun Info-index (topic) - "Look up a string TOPIC in the index for this file. + "Look up a string TOPIC in the index for this manual and go to that entry. If there are no exact matches to the specified topic, this chooses the first match which is a case-insensitive substring of a topic. Use the \\\\[Info-index-next] command to see the other matches. -Give a blank topic name to go to the Index node itself." +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") @@ -2757,6 +2835,11 @@ Give a blank 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))) @@ -2819,7 +2902,11 @@ Give a blank 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) - "(`,' tries to find next)" + (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) @@ -2859,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 @@ -2886,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") @@ -2905,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 () @@ -2996,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 @@ -3013,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\"`({<>})']+\\)") @@ -3051,6 +3152,7 @@ if point is in a menu item description, follow that menu item." (define-key Info-mode-map " " 'Info-scroll-up) (define-key Info-mode-map "\C-m" 'Info-follow-nearest-node) (define-key Info-mode-map "\t" 'Info-next-reference) + (define-key Info-mode-map "\e\t" 'Info-prev-reference) (define-key Info-mode-map [(shift tab)] 'Info-prev-reference) (define-key Info-mode-map [backtab] 'Info-prev-reference) (define-key Info-mode-map "1" 'Info-nth-menu-item) @@ -3160,16 +3262,16 @@ 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-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-history-back "back_arrow" map Info-mode-map) - (tool-bar-local-item-from-menu 'Info-history-forward "fwd_arrow" 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-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-goto-node "jump_to" 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) @@ -3246,14 +3348,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 - (or (and (stringp Info-current-file) - Info-current-file) - buffer-file-name - "")) - ")" 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))) @@ -3317,7 +3419,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-search] command. -\\[Info-index] Look up a topic in this file's Index and move to that node. +\\[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-index] command. \\[info-apropos] Look for a string in the indices of all manuals. \\[Info-goto-node] Move to node specified by name. @@ -3503,10 +3605,6 @@ in the first element of the returned list (which is treated specially in (setq info-file file file-list nil)) (setq file-list (cdr file-list)))))) (Info-find-node info-file "Top") - (or (and (search-forward "\n* menu:" nil t) - (re-search-forward "\n\\* \\(.*\\\\)" nil t)) - (error "Info file `%s' appears to lack an index" info-file)) - (goto-char (match-beginning 1)) ;; Bind Info-history to nil, to prevent the index nodes from ;; getting into the node history. (let ((Info-history nil) @@ -3635,6 +3733,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) @@ -3648,7 +3747,7 @@ the variable `Info-file-list-for-emacs'." (nend (match-end 2)) (tbeg (match-beginning 1)) (tag (match-string 1))) - (if (string-equal tag "Node") + (if (string-equal (downcase tag) "node") (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) @@ -3659,11 +3758,12 @@ the variable `Info-file-list-for-emacs'." ;; Always set up the text property keymap. ;; It will either be used in the buffer ;; or copied in the header line. - (put-text-property tbeg nend 'keymap - (cond - ((equal tag "Prev") Info-prev-link-keymap) - ((equal tag "Next") Info-next-link-keymap) - ((equal tag "Up") Info-up-link-keymap)))))) + (put-text-property + tbeg nend 'keymap + (cond + ((string-equal (downcase tag) "prev") Info-prev-link-keymap) + ((string-equal (downcase tag) "next") Info-next-link-keymap) + ((string-equal (downcase tag) "up" ) Info-up-link-keymap)))))) (when Info-use-header-line (goto-char (point-min)) (let* ((header-end (line-end-position)) @@ -3705,8 +3805,8 @@ the variable `Info-file-list-for-emacs'." ;; underline has the same size as the text. A typical ;; counter example is when a continuation "..." is alone ;; on a line. - (= (- (match-end 1) (match-beginning 1)) - (- (match-end 2) (match-beginning 2)))) + (= (string-width (match-string 1)) + (string-width (match-string 2)))) (let* ((c (preceding-char)) (face (cond ((= c ?*) 'info-title-1) @@ -3735,20 +3835,22 @@ the variable `Info-file-list-for-emacs'." ;; *Note is often used where *note should have been (goto-char start) (skip-syntax-backward " ") + (when (memq (char-before) '(?\( ?\[ ?\{)) + ;; Check whether the paren is preceded by + ;; an end of sentence + (skip-syntax-backward " (")) (setq other-tag - (cond ((memq (char-before) '(nil ?\. ?! ??)) + (cond ((save-match-data (looking-back "\\})']+" 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 @@ -4107,7 +4220,7 @@ INDENT is the current indentation depth." NODESPEC is a string of the form: (file)node." (save-excursion ;; Set up a buffer we can use to fake-out Info. - (set-buffer (get-buffer-create "*info-browse-tmp*")) + (set-buffer (get-buffer-create " *info-browse-tmp*")) (if (not (equal major-mode 'Info-mode)) (Info-mode)) ;; Get the node into this buffer @@ -4171,8 +4284,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