X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/4dacf0ff4bdb950dbc4f168be79426e77c944ecb..409cc4a3ea9e7461572a04f021ff3993e9a516f6:/lisp/info.el diff --git a/lisp/info.el b/lisp/info.el index 1b408f2077..66ca4b6100 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, 2008 Free Software Foundation, Inc. ;; Maintainer: FSF ;; Keywords: help @@ -10,7 +10,7 @@ ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) +;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, @@ -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.") @@ -449,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 @@ -472,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)))))) @@ -523,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, @@ -561,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 () @@ -629,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 `./' @@ -680,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. @@ -690,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) @@ -708,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, @@ -726,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) @@ -851,7 +845,7 @@ a case-insensitive match is tried." (goto-char (point-min)) (condition-case () (if (and (re-search-forward - "makeinfo version \\([0-9]+.[0-9]+\\)" + "makeinfo[ \n]version[ \n]\\([0-9]+.[0-9]+\\)" (line-beginning-position 3) t) (not (version< (match-string 1) "4.7"))) (setq found t)) @@ -893,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. @@ -1206,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)) @@ -1217,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) @@ -1321,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]. @@ -1395,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. @@ -1518,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) @@ -1537,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)) @@ -1629,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)) @@ -1648,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))) @@ -1717,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)) @@ -1812,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 () @@ -1834,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))))))))) @@ -1856,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." @@ -1884,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) ")") @@ -1958,51 +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 ": (" - (propertize (or (file-name-directory file) "") 'invisible t) - (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." @@ -2202,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) @@ -2256,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) @@ -2277,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) @@ -2580,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' @@ -2606,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) @@ -2664,7 +2722,7 @@ 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)) (if Info-file-supports-index-cookies @@ -2757,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") @@ -2776,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))) @@ -2838,8 +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) - (format "(%s total; use `,' for next)" - (length Info-index-alternatives)) + (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) @@ -2879,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 @@ -2906,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") @@ -2925,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 () @@ -3016,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 @@ -3033,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\"`({<>})']+\\)") @@ -3071,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) @@ -3180,16 +3262,20 @@ 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 + :rtl "right-arrow") + (tool-bar-local-item-from-menu 'Info-history-forward "right-arrow" map Info-mode-map + :rtl "left-arrow") + (tool-bar-local-item-from-menu 'Info-prev "prev-node" map Info-mode-map + :rtl "next-node") + (tool-bar-local-item-from-menu 'Info-next "next-node" map Info-mode-map + :rtl "prev-node") + (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-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-index "index" 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) @@ -3266,14 +3352,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))) @@ -3337,7 +3423,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. @@ -3381,7 +3467,7 @@ Advanced commands: (setq widen-automatically nil) (setq desktop-save-buffer 'Info-desktop-buffer-misc-data) (add-hook 'kill-buffer-hook 'Info-kill-buffer nil t) - (add-hook 'clone-buffer-hook 'Info-clone-buffer-hook nil t) + (add-hook 'clone-buffer-hook 'Info-clone-buffer nil t) (add-hook 'change-major-mode-hook 'font-lock-defontify nil t) (add-hook 'isearch-mode-hook 'Info-isearch-start nil t) (set (make-local-variable 'isearch-search-fun-function) @@ -3402,7 +3488,8 @@ Advanced commands: Info-tag-table-buffer (kill-buffer Info-tag-table-buffer))) -(defun Info-clone-buffer-hook () +;; Placed on `clone-buffer-hook'. +(defun Info-clone-buffer () (when (bufferp Info-tag-table-buffer) (setq Info-tag-table-buffer (with-current-buffer Info-tag-table-buffer (clone-buffer)))) @@ -3651,6 +3738,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) @@ -3757,7 +3845,11 @@ the variable `Info-file-list-for-emacs'." ;; 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 @@ -4119,7 +4224,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 @@ -4183,8 +4288,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