]> code.delx.au - gnu-emacs/blobdiff - lisp/info.el
(thai-category-table): Use
[gnu-emacs] / lisp / info.el
index b2a6df32594fbe744454e7ef966be599a8a9e5e6..c2eff14e4247ffcb10da02856efd21db1c3b40e8 100644 (file)
@@ -29,6 +29,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'jka-compr))
+
 (defgroup info nil
   "Info subsystem"
   :group 'help
@@ -59,17 +61,20 @@ The Lisp code is executed when the node is selected.")
   :group 'info)
 
 (defface info-node
-  '((t (:bold t :italic t)))
+  '((((class color)) (:foreground "brown" :bold t :italic t))
+    (t (:bold t :italic t)))
   "Face for Info node names."
   :group 'info)
 
 (defface info-menu-5
-  '((t (:underline t)))
+  '((((class color)) (:foreground "red1"))
+    (t (:underline t)))
   "Face for the fifth and tenth `*' in an Info menu."
   :group 'info)
 
 (defface info-xref
-  '((t (:bold t)))
+  '((((class color)) (:foreground "magenta4" :bold t))
+    (t (:bold t)))
   "Face for Info cross-references."
   :group 'info)
 
@@ -78,34 +83,7 @@ The Lisp code is executed when the node is selected.")
   :type 'integer
   :group 'info)
 
-(defvar Info-directory-list
-  (let ((path (getenv "INFOPATH"))
-       (source (expand-file-name "info/" source-directory))
-       (sibling (if installation-directory
-                    (expand-file-name "info/" installation-directory)))
-       alternative)
-    (if path
-       (split-string path (regexp-quote path-separator))
-      (if (and sibling (file-exists-p sibling))
-         (setq alternative sibling)    ; uninstalled, Emacs builddir != srcdir
-       (setq alternative source))      ; uninstalled, builddir != srcdir
-      (if (or (member alternative Info-default-directory-list)
-             (not (file-exists-p alternative))
-             ;; On DOS/NT, we use movable executables always,
-             ;; and we must always find the Info dir at run time.
-             (if (or (eq system-type 'ms-dos) (eq system-type 'windows-nt))
-                 nil
-               ;; Use invocation-directory for Info only if we used it for
-               ;; exec-directory also.
-               (not (string= exec-directory
-                             (expand-file-name "lib-src/"
-                                               installation-directory)))))
-         Info-default-directory-list
-       ;; `alternative' contains the Info files that came with this
-       ;; version, so we should look there first.  `Info-insert-dir'
-       ;; currently expects to find `alternative' first on the list.
-       (cons alternative
-             (reverse (cdr (reverse Info-default-directory-list)))))))
+(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
 variable INFOPATH to initialize it, or `Info-default-directory-list'
@@ -127,7 +105,8 @@ These directories are not searched for merging the `dir' file."
 (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.")
+It doesn't contain directory names or file name extensions added by Info.
+Can also be t when using `Info-on-current-buffer'.")
 
 (defvar Info-current-subfile nil
   "Info subfile that is actually in the *info* buffer now,
@@ -151,13 +130,14 @@ Marker points nowhere if file has no tag table.")
 
 (defvar Info-standalone nil
   "Non-nil if Emacs was started solely as an Info browser.")
-
+\f
 (defvar Info-suffix-list
   ;; The MS-DOS list should work both when long file names are
   ;; supported (Windows 9X), and when only 8+3 file names are available.
   (if (eq system-type 'ms-dos)
       '( (".gz"      . "gunzip")
         (".z"       . "gunzip")
+        (".bz2"     . "bzip2 -dc")
         (".inz"     . "gunzip")
         (".igz"     . "gunzip")
         (".info.Z"  . "gunzip")
@@ -175,21 +155,25 @@ Marker points nowhere if file has no tag table.")
        (".info.Y".    "unyabba")
        (".info.gz".   "gunzip")
        (".info.z".    "gunzip")
+       (".info.bz2" . "bzip2 -dc")
        (".info".      nil)
        ("-info.Z".   "uncompress")
        ("-info.Y".   "unyabba")
        ("-info.gz".  "gunzip")
+       ("-info.bz2" . "bzip2 -dc")
        ("-info.z".   "gunzip")
        ("-info".     nil)
        ("/index.Z".   "uncompress")
        ("/index.Y".   "unyabba")
        ("/index.gz".  "gunzip")
        ("/index.z".   "gunzip")
+       ("/index.bz2". "bzip2 -dc")
        ("/index".     nil)
        (".Z".         "uncompress")
        (".Y".         "unyabba")
        (".gz".        "gunzip")
        (".z".         "gunzip")
+       (".bz2" .      "bzip2 -dc")
        ("".           nil)))
   "List of file name suffixes and associated decoding commands.
 Each entry should be (SUFFIX . STRING); the file is given to
@@ -265,6 +249,40 @@ Do the right thing if the file has been compressed or zipped."
                                       default-directory)))
            (call-process-region (point-min) (point-max) decoder t t)))
       (insert-file-contents fullname visit))))
+\f
+;; Initialize Info-directory-list, if that hasn't been done yet.
+(defun info-initialize ()
+  (unless Info-directory-list
+    (let ((path (getenv "INFOPATH"))
+         (source (expand-file-name "info/" source-directory))
+         (sibling (if installation-directory
+                      (expand-file-name "info/" installation-directory)))
+         alternative)
+      (setq Info-directory-list
+           (if path
+               (split-string path (regexp-quote path-separator))
+             (if (and sibling (file-exists-p sibling))
+                 ;; Uninstalled, Emacs builddir != srcdir.
+                 (setq alternative sibling)
+               ;; Uninstalled, builddir == srcdir
+               (setq alternative source))
+             (if (or (member alternative Info-default-directory-list)
+                     ;; On DOS/NT, we use movable executables always,
+                     ;; and we must always find the Info dir at run time.
+                     (if (memq system-type '(ms-dos windows-nt))
+                         nil
+                       ;; Use invocation-directory for Info
+                       ;; only if we used it for exec-directory also.
+                       (not (string= exec-directory
+                                     (expand-file-name "lib-src/"
+                                                       installation-directory))))
+                     (not (file-exists-p alternative)))
+                 Info-default-directory-list
+               ;; `alternative' contains the Info files that came with this
+               ;; version, so we should look there first.  `Info-insert-dir'
+               ;; currently expects to find `alternative' first on the list.
+               (cons alternative
+                     (reverse (cdr (reverse Info-default-directory-list))))))))))
 
 ;;;###autoload
 (defun info-other-window (&optional file)
@@ -281,6 +299,8 @@ Do the right thing if the file has been compressed or zipped."
   "Enter Info, the documentation browser.
 Optional argument FILE 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
+`(FILENAME)NODENAME'.
 
 In interactive use, a prefix argument directs this command
 to read a file name from the minibuffer.
@@ -321,7 +341,7 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                                   (nth 1 err) err)))
               (save-buffers-kill-emacs)))
     (info)))
-
+\f
 ;; See if the the accessible portion of the buffer begins with a node
 ;; delimiter, and the node header line which follows matches REGEXP.
 ;; Typically, this test will be followed by a loop that examines the
@@ -346,9 +366,10 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
 ;; no-going-back is non-nil if recovering from an error in this function;
 ;; it says do not attempt further (recursive) error recovery.
 (defun Info-find-node (filename nodename &optional no-going-back)
+  (info-initialize)
   ;; Convert filename to lower case if not found as specified.
   ;; Expand it.
-  (if filename
+  (if (stringp filename)
       (let (temp temp-downcase found)
         (setq filename (substitute-in-file-name filename))
         (if (string= (downcase filename) "dir")
@@ -393,6 +414,22 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                   Info-history)))
   ;; Go into info buffer.
   (or (eq major-mode 'Info-mode) (pop-to-buffer "*info*"))
+  (Info-find-node-2 filename nodename no-going-back))
+
+(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'."
+  (interactive
+   (list (if current-prefix-arg
+            (completing-read "Node name: " (Info-build-node-completions)
+                             nil t "Top")
+          "Top")))
+  (Info-mode)
+  (set (make-local-variable 'Info-current-file) t)
+  (Info-find-node-2 nil nodename))
+
+(defun Info-find-node-2 (filename nodename &optional no-going-back)
   (buffer-disable-undo (current-buffer))
   (or (eq major-mode 'Info-mode)
       (Info-mode))
@@ -517,8 +554,13 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                      (goto-char (setq anchorpos guesspos))
 
                     ;; Else we may have a node, which we search for:
-                   (goto-char (max (point-min)
-                                   (- (byte-to-position guesspos) 1000)))
+                   (let ((guesschar
+                          (or (byte-to-position guesspos)
+                              (if (< (position-bytes (point-max)) guesspos)
+                                  (point-max)
+                                (point-min)))))
+                     (goto-char (max (point-min)
+                                     (- guesschar 1000))))
                     ;; Now search from our advised position
                     ;; (or from beg of buffer)
                     ;; to find the actual node.
@@ -846,7 +888,9 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
        (concat
         "  Info:  ("
         (if Info-current-file
-            (file-name-nondirectory Info-current-file)
+            (file-name-nondirectory (if (stringp Info-current-file)
+                                        Info-current-file
+                                      (or buffer-file-name "")))
           "")
         ")"
         (or Info-current-node ""))))
@@ -854,9 +898,15 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
 ;; Go to an info node specified with a filename-and-nodename string
 ;; of the sort that is found in pointers in nodes.
 
-(defun Info-goto-node (nodename)
-  "Go to info node named NAME.  Give just NODENAME or (FILENAME)NODENAME."
-  (interactive (list (Info-read-node-name "Goto node: ")))
+(defun Info-goto-node (nodename &optional fork)
+  "Go to info node named NAME.  Give just NODENAME or (FILENAME)NODENAME.
+If FORK is non-nil, show the node in a new info buffer.
+If FORK is a string, it is the name to use for the new buffer."
+  (interactive (list (Info-read-node-name "Goto node: ") current-prefix-arg))
+  (info-initialize)
+  (if fork
+    (set-buffer
+     (clone-buffer (concat "*info-" (if (stringp fork) fork nodename) "*") t)))
   (let (filename)
     (string-match "\\s *\\((\\s *\\([^\t)]*\\)\\s *)\\s *\\|\\)\\(.*\\)"
                  nodename)
@@ -916,15 +966,13 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                  (goto-char marker)
                  (while (re-search-forward "\nNode: \\(.*\\)\177" nil t)
                    (setq compl
-                         (cons (list (buffer-substring (match-beginning 1)
-                                                       (match-end 1)))
+                         (cons (list (match-string-no-properties 1))
                                compl))))
              (widen)
              (goto-char (point-min))
              ;; If the buffer begins with a node header, process that first.
              (if (Info-node-at-bob-matching node-regexp)
-                 (setq compl (list (buffer-substring (match-beginning 1)
-                                                     (match-end 1)))))
+                 (setq compl (list (match-string-no-properties 1))))
              ;; Now for the rest of the nodes.
              (while (search-forward "\n\^_" nil t)
                (forward-line 1)
@@ -932,9 +980,9 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                  (forward-line 1)
                  (if (re-search-backward node-regexp beg t)
                      (setq compl 
-                           (cons (list (buffer-substring (match-beginning 1)
-                                                         (match-end 1)))
+                           (cons (list (match-string-no-properties 1))
                                  compl))))))))
+       (setq compl (cons '("*") compl))
        (setq Info-current-file-completions compl))))
 \f
 (defun Info-restore-point (hl)
@@ -991,8 +1039,7 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
                      (re-search-forward "\\(^.*\\): [0-9]+$")
                      (goto-char (+ (match-end 1) 2))
                      (setq list (cons (cons (read (current-buffer))
-                                            (buffer-substring
-                                             (match-beginning 1) (match-end 1)))
+                                            (match-string-no-properties 1))
                                       list))
                      (goto-char (1+ (match-end 0))))
                    (setq list (nreverse list)
@@ -1069,7 +1116,7 @@ In standalone mode, \\<Info-mode-map>\\[Info-exit] exits Emacs itself."
 If SAME-FILE is non-nil, do not move to a different Info file."
   (interactive)
   (let ((node (Info-extract-pointer "up")))
-    (and same-file
+    (and (or same-file (not (stringp Info-current-file)))
         (string-match "^(" node)
         (error "Up node is in another Info file"))
     (Info-goto-node node))
@@ -1110,7 +1157,7 @@ NAME may be an abbreviation of the reference name."
 
        (goto-char (point-min))
        (while (re-search-forward "\\*note[ \n\t]*\\([^:]*\\):" nil t)
-        (setq str (buffer-substring
+        (setq str (buffer-substring-no-properties
                    (match-beginning 1)
                    (1- (point))))
         ;; See if this one should be the default.
@@ -1218,12 +1265,10 @@ NAME may be an abbreviation of the reference name."
               (goto-char (point-min))
               (search-forward "\n* Menu:")
               (while (re-search-forward pattern nil t)
-                (setq completions (cons (cons (format "%s"
-                                                      (buffer-substring
-                                                       (match-beginning 1)
-                                                       (match-end 1)))
-                                              (match-beginning 1))
-                                        completions))))
+                (setq completions
+                      (cons (cons (match-string-no-properties 1)
+                                  (match-beginning 1))
+                            completions))))
             (try-completion string completions predicate)))
          ((eq action t)
           (let (completions
@@ -1235,11 +1280,9 @@ NAME may be an abbreviation of the reference name."
               (goto-char (point-min))
               (search-forward "\n* Menu:")
               (while (re-search-forward pattern nil t)
-                (setq completions (cons (cons (format "%s"
-                                                      (buffer-substring
-                                                       (match-beginning 1)
-                                                       (match-end 1)))
-                                              (match-beginning 1))
+                (setq completions (cons (cons
+                                         (match-string-no-properties 1)
+                                         (match-beginning 1))
                                         completions))))
             (all-completions string completions predicate)))
          (t
@@ -1253,7 +1296,7 @@ NAME may be an abbreviation of the reference name."
                                nil t))))))
 
 
-(defun Info-menu (menu-item)
+(defun Info-menu (menu-item &optional fork)
   "Go to node for menu item named (or abbreviated) NAME.
 Completion is allowed, and the menu item point is on is the default."
   (interactive
@@ -1273,9 +1316,7 @@ Completion is allowed, and the menu item point is on is the default."
              (goto-char p)
              (end-of-line)
              (if (re-search-backward "\n\\* +\\([^:\t\n]*\\):" beg t)
-                 (setq default (format "%s" (buffer-substring
-                                             (match-beginning 1)
-                                             (match-end 1))))))))
+                 (setq default (match-string-no-properties 1))))))
      (let ((item nil))
        (while (null item)
         (setq item (let ((completion-ignore-case t)
@@ -1293,10 +1334,10 @@ Completion is allowed, and the menu item point is on is the default."
                 (setq item default)
                 ;; ask again
                 (setq item nil))))
-       (list item))))
+       (list item current-prefix-arg))))
   ;; there is a problem here in that if several menu items have the same
   ;; name you can only go to the node of the first with this command.
-  (Info-goto-node (Info-extract-menu-item menu-item)))
+  (Info-goto-node (Info-extract-menu-item menu-item) (if fork menu-item)))
   
 (defun Info-extract-menu-item (menu-item)
   (setq menu-item (regexp-quote menu-item))
@@ -1612,15 +1653,11 @@ Give a blank topic name to go to the Index node itself."
                (goto-char (point-min))
                (while (re-search-forward pattern nil t)
                  (setq matches
-                       (cons (list (buffer-substring (match-beginning 1)
-                                                     (match-end 1))
-                                   (buffer-substring (match-beginning 2)
-                                                     (match-end 2))
+                       (cons (list (match-string-no-properties 1)
+                                   (match-string-no-properties 2)
                                    Info-current-node
                                    (string-to-int (concat "0"
-                                                          (buffer-substring
-                                                           (match-beginning 3)
-                                                           (match-end 3)))))
+                                                          (match-string 3))))
                              matches)))
                (and (setq node (Info-extract-pointer "next" t))
                     (string-match "\\<Index\\>" node)))
@@ -1742,7 +1779,7 @@ SIG optional fourth argument, controls action on no match
                                          (> (match-end 0) pos))))))
        (if (and found (<= (match-beginning 0) pos)
                 (> (match-end 0) pos))
-           (buffer-substring (match-beginning 1) (match-end 1))
+           (match-string-no-properties 1)
          (cond ((null errorstring)
                 nil)
                ((eq errorstring t)
@@ -1839,6 +1876,7 @@ If no reference to follow, moves to the next node, or up if none."
   (define-key Info-mode-map "s" 'Info-search)
   ;; For consistency with Rmail.
   (define-key Info-mode-map "\M-s" 'Info-search)
+  (define-key Info-mode-map "\M-n" 'clone-buffer)
   (define-key Info-mode-map "t" 'Info-top-node)
   (define-key Info-mode-map "u" 'Info-up)
   (define-key Info-mode-map "," 'Info-index-next)
@@ -2014,9 +2052,20 @@ Advanced commands:
   ;; 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 (make-local-hook 'clone-buffer-hook) 'Info-clone-buffer-hook nil t)
   (Info-set-mode-line)
   (run-hooks 'Info-mode-hook))
 
+(defun Info-clone-buffer-hook ()
+  (when (bufferp Info-tag-table-buffer)
+    (setq Info-tag-table-buffer
+         (with-current-buffer Info-tag-table-buffer (clone-buffer)))
+    (let ((m Info-tag-table-marker))
+      (when (and (markerp m) (marker-position m))
+       (setq Info-tag-table-marker
+             (with-current-buffer Info-tag-table-buffer
+               (copy-marker (marker-position m))))))))
+
 (defvar Info-edit-map nil
   "Local keymap used within `e' command of Info.")
 (if Info-edit-map
@@ -2069,7 +2118,8 @@ Allowed only if variable `Info-enable-edit' is non-nil."
        (message "Tags may have changed.  Use Info-tagify if necessary")))
 \f
 (defvar Info-file-list-for-emacs
-  '("ediff" "forms" "gnus" "info" ("mh" . "mh-e") "sc")
+  '("ediff" "forms" "gnus" "info" ("mh" . "mh-e") "sc" "message"
+    ("dired" . "dired-x") ("c" . "ccmode") "viper")
   "List of Info files that describe Emacs commands.
 An element can be a file name, or a list of the form (PREFIX . FILE)
 where PREFIX is a name prefix and FILE is the file to look in.
@@ -2115,9 +2165,7 @@ The locations are of the format used in Info-history, i.e.
       (goto-char (point-max))
       (while (re-search-backward cmd-desc nil t)
          (setq where (cons (list Info-current-file
-                                 (buffer-substring
-                                  (match-beginning 1)
-                                  (match-end 1))
+                                 (match-string-no-properties 1)
                                  0)
                            where)))
       where)))