]> code.delx.au - gnu-emacs/blobdiff - lisp/man.el
*** empty log message ***
[gnu-emacs] / lisp / man.el
index 406085a094f428715abb9c54f42eb29e24604959..855565242e2e289e1b34cea73da19f98a6caa177 100644 (file)
@@ -1,11 +1,11 @@
 ;;; man.el --- browse UNIX manual pages
 
-;; Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1996, 1997, 2001 Free Software Foundation, Inc.
 
-;; Author:             Barry A. Warsaw <bwarsaw@cen.com>
+;; Author: Barry A. Warsaw <bwarsaw@cen.com>
 ;; Maintainer: FSF
-;; Keywords:           help
-;; Adapted-By:         ESR, pot
+;; Keywords: help
+;; Adapted-By: ESR, pot
 
 ;; This file is part of GNU Emacs.
 
@@ -81,7 +81,7 @@
 ;;   footer).  A different algorithm should be used.  It is easy to
 ;;   compute how many blank lines there are before and after the page
 ;;   headers, and after the page footer.  But it is possible to compute
-;;   the number of blank lines before the page footer by euristhics
+;;   the number of blank lines before the page footer by heuristics
 ;;   only.  Is it worth doing?
 ;; - Allow a user option to mean that all the manpages should go in
 ;;   the same buffer, where they can be browsed with M-n and M-p.
@@ -225,20 +225,6 @@ the associated section number."
 (defvar Man-awk-command "awk"
   "Command used for processing awk scripts.")
 
-(defvar Man-mode-line-format
-  '("-"
-    mode-line-mule-info
-    mode-line-modified
-    mode-line-frame-identification
-    mode-line-buffer-identification "  "
-    global-mode-string
-    " " Man-page-mode-string
-    "  %[(" mode-name mode-line-process minor-mode-alist "%n)%]--"
-    (line-number-mode "L%l--")
-    (column-number-mode "C%c--")
-    (-3 . "%p") "-%-")
-  "Mode line format for manual mode buffer.")
-
 (defvar Man-mode-map nil
   "Keymap for Man mode.")
 
@@ -276,10 +262,19 @@ This regular expression should start with a `^' character.")
 
 (defvar Man-reference-regexp
   (concat "\\(" Man-name-regexp "\\)(\\(" Man-section-regexp "\\))")
+  "Regular expression describing a reference to another manpage.")
+
+;; This includes the section as an optional part to catch hyphenated
+;; refernces to manpages.
+(defvar Man-hyphenated-reference-regexp
+  (concat "\\(" Man-name-regexp "\\)\\((\\(" Man-section-regexp "\\))\\)?")
   "Regular expression describing a reference in the SEE ALSO section.")
 
 (defvar Man-switches ""
-  "Switches passed to the man command, as a single string.")
+  "Switches passed to the man command, as a single string.
+
+If you want to be able to see all the manpages for a subject you type,
+make -a one of the switches, if your `man' program supports it.")
 
 (defvar Man-specified-section-option
   (if (string-match "-solaris[0-9.]*$" system-configuration)
@@ -356,6 +351,7 @@ This regular expression should start with a `^' character.")
   (define-key Man-mode-map "q"    'Man-quit)
   (define-key Man-mode-map "m"    'man)
   (define-key Man-mode-map "\r"   'man-follow)
+  (define-key Man-mode-map [mouse-2]   'man-follow-mouse)
   (define-key Man-mode-map "?"    'describe-mode)
   )
 
@@ -423,16 +419,6 @@ This is necessary if one wants to dump man.el with Emacs."
           )))
 )
 
-(defsubst Man-match-substring (&optional n string)
-  "Return the substring matched by the last search.
-Optional arg N means return the substring matched by the Nth paren
-grouping.  Optional second arg STRING means return a substring from
-that string instead of from the current buffer."
-  (if (null n) (setq n 0))
-  (if string
-      (substring string (match-beginning n) (match-end n))
-    (buffer-substring (match-beginning n) (match-end n))))
-
 (defsubst Man-make-page-mode-string ()
   "Formats part of the mode line for Man mode."
   (format "%s page %d of %d"
@@ -476,13 +462,13 @@ and the Man-section-translations-alist variables)."
     (cond
      ;; "chmod(2V)" case ?
      ((string-match (concat "^" Man-reference-regexp "$") ref)
-      (setq name (Man-match-substring 1 ref)
-           section (Man-match-substring 2 ref)))
+      (setq name (match-string 1 ref)
+           section (match-string 2 ref)))
      ;; "2v chmod" case ?
      ((string-match (concat "^\\(" Man-section-regexp
                            "\\) +\\(" Man-name-regexp "\\)$") ref)
-      (setq name (Man-match-substring 2 ref)
-           section (Man-match-substring 1 ref))))
+      (setq name (match-string 2 ref)
+           section (match-string 1 ref))))
     (if (string= name "")
        ref                             ; Return the reference as is
       (if Man-downcase-section-letters-flag
@@ -511,7 +497,10 @@ This guess is based on the text surrounding the cursor."
     (save-excursion
       ;; Default man entry title is any word the cursor is on, or if
       ;; cursor not on a word, then nearest preceding word.
-      (setq word (current-word))
+      (skip-chars-backward "-a-zA-Z0-9._+:")
+      (let ((start (point)))
+       (skip-chars-forward "-a-zA-Z0-9._+:")
+       (setq word (buffer-substring start (point))))
       (if (string-match "[._]+$" word)
          (setq word (substring word 0 (match-beginning 0))))
       ;; If looking at something like ioctl(2) or brc(1M), include the
@@ -522,7 +511,7 @@ This guess is based on the text surrounding the cursor."
              word
              (if (looking-at
                   (concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
-                 (format "(%s)" (Man-match-substring 1))
+                 (format "(%s)" (match-string 1))
                "")))))
 
 \f
@@ -543,18 +532,19 @@ results in a Man mode (manpage browsing) buffer.  See variable
 If a buffer already exists for this man page, it will display immediately.
 
 To specify a man page from a certain section, type SUBJECT(SECTION) or
-SECTION SUBJECT when prompted for a manual entry."
+SECTION SUBJECT when prompted for a manual entry.  To see manpages from
+all sections related to a subject, put something appropriate into the
+`Man-switches' variable, which see."
   (interactive
    (list (let* ((default-entry (Man-default-man-entry))
                (input (read-string
                        (format "Manual entry%s: "
                                (if (string= default-entry "")
                                    ""
-                                 (format " (default %s)" default-entry))))))
+                                 (format " (default %s)" default-entry)))
+                       nil nil default-entry)))
           (if (string= input "")
-              (if (string= default-entry "")
-                  (error "No man args given")
-                default-entry)
+              (error "No man args given")
             input))))
 
   ;; Possibly translate the "subject(section)" syntax into the
@@ -572,6 +562,13 @@ SECTION SUBJECT when prompted for a manual entry."
       (error "No item under point")
     (man man-args)))
 
+(defun man-follow-mouse (e)
+  "Get a Un*x manual page of the item under the mouse and put it in a buffer."
+  (interactive "e")
+  (save-excursion
+    (mouse-set-point e)
+    (call-interactively 'man-follow)))
+
 (defun Man-getpage-in-background (topic)
   "Use TOPIC to build and fire off the manpage and cleaning command."
   (let* ((man-args topic)
@@ -599,12 +596,31 @@ SECTION SUBJECT when prompted for a manual entry."
            (default-directory "/"))
        ;; Prevent any attempt to use display terminal fanciness.
        (setenv "TERM" "dumb")
+       ;; In Debian Woody, at least, we get overlong lines under X
+       ;; unless COLUMNS or MANWIDTH is set.  This isn't a problem on
+       ;; a tty.  man(1) says:
+       ;;        MANWIDTH
+       ;;               If $MANWIDTH is set, its value is used as the  line
+       ;;               length  for which manual pages should be formatted.
+       ;;               If it is not set, manual pages  will  be  formatted
+       ;;               with  a line length appropriate to the current ter-
+       ;;               minal (using an ioctl(2) if available, the value of
+       ;;               $COLUMNS,  or falling back to 80 characters if nei-
+       ;;               ther is available).
+       (if window-system
+           (unless (or (getenv "MANWIDTH") (getenv "COLUMNS"))
+             ;; This isn't strictly correct, since we don't know how
+             ;; the page will actually be displayed, but it seems
+             ;; reasonable.
+             (setenv "COLUMNS" (number-to-string (frame-width)))))
        (if (fboundp 'start-process)
            (set-process-sentinel
             (start-process manual-program buffer "sh" "-c"
                            (format (Man-build-man-command) man-args))
             'Man-bgproc-sentinel)
-         (progn
+         (let ((process-environment 
+                (cons "GROFF_NO_SGR=1" process-environment)))
+
            (let ((exit-status
                   (call-process shell-file-name nil (list buffer nil) nil "-c"
                                 (format (Man-build-man-command) man-args)))
@@ -662,7 +678,7 @@ See the variable `Man-notify-method' for the different notification behaviors."
      )))
 
 (defun Man-softhyphen-to-minus ()
-  ;; \255 is some kind of dash in Latin-N.  Versions of Debian man, at
+  ;; \255 is SOFT HYPHEN in Latin-N.  Versions of Debian man, at
   ;; least, emit it even when not in a Latin-N locale.
   (unless (eq t (compare-strings "latin-" 0 nil
                                 current-language-environment 0 6 t))
@@ -716,6 +732,11 @@ Same for the ANSI bold and normal escape sequences."
   (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t)
     (replace-match "+")
     (put-text-property (1- (point)) (point) 'face 'bold))
+  (goto-char (point-min))
+  ;; Try to recognize common forms of cross references.
+  (while (re-search-forward "\\w+([0-9].?)" nil t)
+    (put-text-property (match-beginning 0) (match-end 0)
+                      'mouse-face 'highlight))
   (Man-softhyphen-to-minus)
   (message "%s man page made up" Man-arguments))
 
@@ -832,7 +853,6 @@ The following variables may be of some use.  Try
 `Man-circular-pages-flag'      Treat multiple manpage list as circular.
 `Man-section-translations-alist' List of section numbers and their Un*x equiv.
 `Man-filter-list'              Background manpage filter command.
-`Man-mode-line-format'         Mode line format for Man mode buffers.
 `Man-mode-map'                 Keymap bindings for Man mode buffers.
 `Man-mode-hook'                        Normal hook run on entry to Man mode.
 `Man-section-regexp'           Regexp describing manpage section letters.
@@ -848,7 +868,9 @@ The following key bindings are currently in effect in the buffer:
   (setq major-mode 'Man-mode
        mode-name "Man"
        buffer-auto-save-file-name nil
-       mode-line-format Man-mode-line-format
+       mode-line-buffer-identification
+       (list (default-value 'mode-line-buffer-identification)
+             " {" 'Man-page-mode-string "}")
        truncate-lines t
        buffer-read-only t)
   (buffer-disable-undo (current-buffer))
@@ -867,7 +889,7 @@ The following key bindings are currently in effect in the buffer:
   (goto-char (point-min))
   (let ((case-fold-search nil))
     (while (re-search-forward Man-heading-regexp (point-max) t)
-      (aput 'Man-sections-alist (Man-match-substring 1))
+      (aput 'Man-sections-alist (match-string 1))
       (forward-line 1))))
 
 (defsubst Man-build-references-alist ()
@@ -887,16 +909,21 @@ The following key bindings are currently in effect in the buffer:
            (back-to-indentation)
            (while (and (not (eobp)) (/= (point) runningpoint))
              (setq runningpoint (point))
-             (if (re-search-forward Man-reference-regexp end t)
-                 (let* ((word (Man-match-substring 0))
+             (if (re-search-forward Man-hyphenated-reference-regexp end t)
+                 (let* ((word (match-string 0))
                         (len (1- (length word))))
                    (if hyphenated
                        (setq word (concat hyphenated word)
-                             hyphenated nil))
+                             hyphenated nil
+                             ;; Update len, in case a reference spans
+                             ;; more than two lines (paranoia).
+                             len (1- (length word))))
                    (if (= (aref word len) ?-)
-                       (setq hyphenated (substring word 0 len))
-                     (aput 'Man-refpages-alist word))))
-             (skip-chars-forward " \t\n,")))))))
+                       (setq hyphenated (substring word 0 len)))
+                   (if (string-match Man-reference-regexp word)
+                       (aput 'Man-refpages-alist word))))
+             (skip-chars-forward " \t\n,"))))))
+  (setq Man-refpages-alist (nreverse Man-refpages-alist)))
 
 (defun Man-build-page-list ()
   "Build the list of separate manpages in the buffer."
@@ -909,7 +936,7 @@ The following key bindings are currently in effect in the buffer:
     (while (not (eobp))
       (setq header
            (if (looking-at Man-page-header-regexp)
-               (Man-match-substring 1)
+               (match-string 1)
              nil))
       ;; Go past both the current and the next Man-first-heading-regexp
       (if (re-search-forward Man-first-heading-regexp nil 'move 2)
@@ -1045,13 +1072,33 @@ Returns t if section is found, nil otherwise."
   (Man-find-section (aheadsym Man-sections-alist)))
 
 (defun Man-goto-see-also-section ()
-  "Move point the the \"SEE ALSO\" section.
+  "Move point to the \"SEE ALSO\" section.
 Actually the section moved to is described by `Man-see-also-regexp'."
   (interactive)
   (if (not (Man-find-section Man-see-also-regexp))
       (error (concat "No " Man-see-also-regexp
                     " section found in the current manpage"))))
 
+(defun Man-possibly-hyphenated-word ()
+  "Return a possibly hyphenated word at point.
+If the word starts at the first non-whitespace column, and the
+previous line ends with a hyphen, return the last word on the previous
+line instead.  Thus, if a reference to \"tcgetpgrp(3V)\" is hyphenated
+as \"tcgetp-grp(3V)\", and point is at \"grp(3V)\", we return
+\"tcgetp-\" instead of \"grp\"."
+  (save-excursion
+    (skip-syntax-backward "w()")
+    (skip-chars-forward " \t")
+    (let ((beg (point))
+         (word (current-word)))
+      (when (eq beg (save-excursion
+                     (back-to-indentation)
+                     (point)))
+       (end-of-line 0)
+       (if (eq (char-before) ?-)
+           (setq word (current-word))))
+      word)))
+
 (defun Man-follow-manual-reference (reference)
   "Get one of the manpages referred to in the \"SEE ALSO\" section.
 Specify which REFERENCE to use; default is based on word at point."
@@ -1059,18 +1106,15 @@ Specify which REFERENCE to use; default is based on word at point."
    (if (not Man-refpages-alist)
        (error "There are no references in the current man page")
      (list (let* ((default (or
-                            (car (all-completions
-                                  (save-excursion
-                                    (skip-syntax-backward "w()")
-                                    (skip-chars-forward " \t")
-                                    (let ((word (current-word)))
-                                      ;; strip a trailing '-':
-                                      (if (string-match "-$" word)
-                                          (substring word 0
-                                                     (match-beginning 0))
-                                        word)))
-                                  Man-refpages-alist))
-                            (aheadsym Man-refpages-alist)))
+                           (car (all-completions
+                                 (let ((word (Man-possibly-hyphenated-word)))
+                                   ;; strip a trailing '-':
+                                   (if (string-match "-$" word)
+                                       (substring word 0
+                                                  (match-beginning 0))
+                                     word))
+                                 Man-refpages-alist))
+                           (aheadsym Man-refpages-alist)))
                   chosen
                   (prompt (concat "Refer to: (default " default ") ")))
              (setq chosen (completing-read prompt Man-refpages-alist nil t))