]> code.delx.au - gnu-emacs/blobdiff - lisp/man.el
* vc/vc-hooks.el (vc-before-save): Clear cache if file has been
[gnu-emacs] / lisp / man.el
index c8c2f8653e214c262dcaf36df63a45cdb15e1a3a..ca7df4cd1a4ccca12456abe46ee31377eb1ed3e6 100644 (file)
@@ -1,6 +1,6 @@
 ;;; man.el --- browse UNIX manual pages -*- coding: iso-8859-1 -*-
 
-;; Copyright (C) 1993-1994, 1996-1997, 2001-2011
+;; Copyright (C) 1993-1994, 1996-1997, 2001-2012
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Barry A. Warsaw <bwarsaw@cen.com>
@@ -89,7 +89,6 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl))
-(require 'assoc)
 (require 'button)
 
 ;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
@@ -215,15 +214,27 @@ the associated section number."
                       (string :tag "Real Section")))
   :group 'man)
 
+;; FIXME see comments at ffap-c-path.
 (defcustom Man-header-file-path
-  '("/usr/include" "/usr/local/include")
+  (let ((arch (with-temp-buffer
+                (when (eq 0 (ignore-errors
+                              (call-process "gcc" nil '(t nil) nil
+                                            "-print-multiarch")))
+                  (goto-char (point-min))
+                  (buffer-substring (point) (line-end-position)))))
+        (base '("/usr/include" "/usr/local/include")))
+    (if (zerop (length arch))
+        base
+      (append base (list (expand-file-name arch "/usr/include")))))
   "C Header file search path used in Man."
+  :version "24.1"                       ; add multiarch
   :type '(repeat string)
   :group 'man)
 
 (defcustom Man-name-local-regexp (concat "^" (regexp-opt '("NOM" "NAME")) "$")
   "Regexp that matches the text that precedes the command's name.
 Used in `bookmark-set' to get the default bookmark name."
+  :version "24.1"
   :type 'string :group 'bookmark)
 
 (defvar manual-program "man"
@@ -254,8 +265,7 @@ Used in `bookmark-set' to get the default bookmark name."
   "Regular expression describing a manpage section within parentheses.")
 
 (defvar Man-page-header-regexp
-  (if (and (string-match "-solaris2\\." system-configuration)
-          (not (string-match "-solaris2\\.[123435]$" system-configuration)))
+  (if (string-match "-solaris2\\." system-configuration)
       (concat "^[-A-Za-z0-9_].*[ \t]\\(" Man-name-regexp
              "(\\(" Man-section-regexp "\\))\\)$")
     (concat "^[ \t]*\\(" Man-name-regexp
@@ -277,7 +287,9 @@ This regexp should not start with a `^' character.")
 This regular expression should start with a `^' character.")
 
 (defvar Man-reference-regexp
-  (concat "\\(" Man-name-regexp "\\)[ \t]*(\\(" Man-section-regexp "\\))")
+  (concat "\\(" Man-name-regexp
+         "\\(\n[ \t]+" Man-name-regexp "\\)*\\)[ \t]*(\\("
+         Man-section-regexp "\\))")
   "Regular expression describing a reference to another manpage.")
 
 (defvar Man-apropos-regexp
@@ -347,10 +359,10 @@ Otherwise, the value is whatever the function
 (make-variable-buffer-local 'Man-arguments)
 (put 'Man-arguments 'permanent-local t)
 
-(defvar Man-sections-alist nil)
-(make-variable-buffer-local 'Man-sections-alist)
-(defvar Man-refpages-alist nil)
-(make-variable-buffer-local 'Man-refpages-alist)
+(defvar Man--sections nil)
+(make-variable-buffer-local 'Man--sections)
+(defvar Man--refpages nil)
+(make-variable-buffer-local 'Man--refpages)
 (defvar Man-page-list nil)
 (make-variable-buffer-local 'Man-page-list)
 (defvar Man-current-page 0)
@@ -397,8 +409,8 @@ Otherwise, the value is whatever the function
     (suppress-keymap map)
     (set-keymap-parent map button-buffer-map)
 
-    (define-key map " "    'scroll-up)
-    (define-key map "\177" 'scroll-down)
+    (define-key map " "    'scroll-up-command)
+    (define-key map "\177" 'scroll-down-command)
     (define-key map "n"    'Man-next-section)
     (define-key map "p"    'Man-previous-section)
     (define-key map "\en"  'Man-next-manpage)
@@ -598,8 +610,8 @@ and the `Man-section-translations-alist' variables)."
     (cond
      ;; "chmod(2V)" case ?
      ((string-match (concat "^" Man-reference-regexp "$") ref)
-      (setq name (match-string 1 ref)
-           section (match-string 2 ref)))
+      (setq name (replace-regexp-in-string "[\n\t ]" "" (match-string 1 ref))
+           section (match-string 3 ref)))
      ;; "2v chmod" case ?
      ((string-match (concat "^\\(" Man-section-regexp
                            "\\) +\\(" Man-name-regexp "\\)$") ref)
@@ -686,7 +698,7 @@ POS defaults to `point'."
          ;; Otherwise record the current column and look backwards.
          (setq column (current-column))
          (skip-chars-backward ",; \t")
-         ;; Record the distance travelled.
+         ;; Record the distance traveled.
          (setq distance (- column (current-column)))
          (when (looking-back
                 (concat "([ \t]*\\(?:" Man-section-regexp "\\)[ \t]*)"))
@@ -753,8 +765,10 @@ POS defaults to `point'."
 
 (defun Man-completion-table (string pred action)
   (cond
-   ((eq action 'lambda)
-    (not (string-match "([^)]*\\'" string)))
+   ;; This ends up returning t for pretty much any string, and hence leads to
+   ;; spurious "complete but not unique" messages.  And since `man' doesn't
+   ;; require-match anyway, there's not point being clever.
+   ;;((eq action 'lambda) (not (string-match "([^)]*\\'" string)))
    ((equal string "-k")
     ;; Let SPC (minibuffer-complete-word) insert the space.
     (complete-with-action action '("-k ") string pred))
@@ -930,7 +944,8 @@ Return the buffer in which the manpage will appear."
        ;;               minal (using an ioctl(2) if available, the value of
        ;;               $COLUMNS,  or falling back to 80 characters if nei-
        ;;               ther is available).
-       (unless (or (getenv "MANWIDTH") (getenv "COLUMNS"))
+       (when (or window-system
+                  (not (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.
@@ -1094,7 +1109,7 @@ Same for the ANSI bold and normal escape sequences."
       (replace-match "+")
       (put-text-property (1- (point)) (point) 'face 'bold))
     ;; When the header is longer than the manpage name, groff tries to
-    ;; condense it to a shorter line interspered with ^H.  Remove ^H with
+    ;; condense it to a shorter line interspersed with ^H.  Remove ^H with
     ;; their preceding chars (but don't put Man-overstrike-face).  (Bug#5566)
     (goto-char (point-min))
     (while (re-search-forward ".\b" nil t) (backward-delete-char 2))
@@ -1107,7 +1122,7 @@ Same for the ANSI bold and normal escape sequences."
       (put-text-property (match-beginning 0)
                         (match-end 0)
                         'face Man-overstrike-face)))
-  (message "%s man page formatted" Man-arguments))
+  (message "%s man page formatted" (Man-page-from-arguments Man-arguments)))
 
 (defun Man-highlight-references (&optional xref-man-type)
   "Highlight the references on mouse-over.
@@ -1188,7 +1203,7 @@ script would have done them."
   (goto-char (point-min))
   (while (re-search-forward "[-|]\\(\b[-|]\\)+" nil t) (replace-match "+"))
   ;; When the header is longer than the manpage name, groff tries to
-  ;; condense it to a shorter line interspered with ^H.  Remove ^H with
+  ;; condense it to a shorter line interspersed with ^H.  Remove ^H with
   ;; their preceding chars (but don't put Man-overstrike-face).  (Bug#5566)
   (goto-char (point-min))
   (while (re-search-forward ".\b" nil t) (backward-delete-char 2))
@@ -1256,12 +1271,11 @@ manpage command."
          (Man-mode)
 
          (if (not Man-page-list)
-             (let ((args Man-arguments))
+             (let ((args Man-arguments))
                (kill-buffer (current-buffer))
-               (error "Can't find the %s manpage" args)))
-
-          (set-buffer-modified-p nil)
-          ))
+               (user-error "Can't find the %s manpage"
+                            (Man-page-from-arguments args)))
+           (set-buffer-modified-p nil))))
        ;; Restore case-fold-search before calling
        ;; Man-notify-when-ready because it may switch buffers.
 
@@ -1272,6 +1286,18 @@ manpage command."
            (error "%s" err-mess))
        ))))
 
+(defun Man-page-from-arguments (args)
+  ;; Skip arguments and only print the page name.
+  (mapconcat
+   'identity
+   (delete nil
+          (mapcar
+           (lambda (elem)
+             (and (not (string-match "^-" elem))
+                  elem))
+           (split-string args " ")))
+   " "))
+
 \f
 ;; ======================================================================
 ;; set up manual mode in buffer and build alists
@@ -1343,17 +1369,19 @@ The following key bindings are currently in effect in the buffer:
   (run-mode-hooks 'Man-mode-hook))
 
 (defsubst Man-build-section-alist ()
-  "Build the association list of manpage sections."
-  (setq Man-sections-alist nil)
+  "Build the list of manpage sections."
+  (setq Man--sections nil)
   (goto-char (point-min))
   (let ((case-fold-search nil))
     (while (re-search-forward Man-heading-regexp (point-max) t)
-      (aput 'Man-sections-alist (match-string 1))
+      (let ((section (match-string 1)))
+        (unless (member section Man--sections)
+          (push section Man--sections)))
       (forward-line 1))))
 
 (defsubst Man-build-references-alist ()
-  "Build the association list of references (in the SEE ALSO section)."
-  (setq Man-refpages-alist nil)
+  "Build the list of references (in the SEE ALSO section)."
+  (setq Man--refpages nil)
   (save-excursion
     (if (Man-find-section Man-see-also-regexp)
        (let ((start (progn (forward-line 1) (point)))
@@ -1379,10 +1407,11 @@ The following key bindings are currently in effect in the buffer:
                              len (1- (length word))))
                    (if (memq (aref word len) '(?- ?­))
                        (setq hyphenated (substring word 0 len)))
-                   (if (string-match Man-reference-regexp word)
-                       (aput 'Man-refpages-alist word))))
+                   (and (string-match Man-reference-regexp word)
+                         (not (member word Man--refpages))
+                         (push word Man--refpages))))
              (skip-chars-forward " \t\n,"))))))
-  (setq Man-refpages-alist (nreverse Man-refpages-alist)))
+  (setq Man--refpages (nreverse Man--refpages)))
 
 (defun Man-build-page-list ()
   "Build the list of separate manpages in the buffer."
@@ -1446,7 +1475,12 @@ The following key bindings are currently in effect in the buffer:
            (nindent 0))
        (narrow-to-region (car page) (car (cdr page)))
        (if Man-uses-untabify-flag
-           (untabify (point-min) (point-max)))
+           ;; The space characters inserted by `untabify' inherit
+           ;; sticky text properties, which is unnecessary and looks
+           ;; ugly with underlining (Bug#11408).
+           (let ((text-property-default-nonsticky
+                  (cons '(face . t) text-property-default-nonsticky)))
+             (untabify (point-min) (point-max))))
        (if (catch 'unindent
              (goto-char (point-min))
              (if (not (re-search-forward Man-first-heading-regexp nil t))
@@ -1514,21 +1548,22 @@ Returns t if section is found, nil otherwise."
       nil)
     ))
 
-(defun Man-goto-section ()
-  "Query for section to move point to."
-  (interactive)
-  (aput 'Man-sections-alist
-       (let* ((default (aheadsym Man-sections-alist))
-              (completion-ignore-case t)
-              chosen
-              (prompt (concat "Go to section (default " default "): ")))
-         (setq chosen (completing-read prompt Man-sections-alist))
-         (if (or (not chosen)
-                 (string= chosen ""))
-             default
-           chosen)))
-  (unless (Man-find-section (aheadsym Man-sections-alist))
-    (error "Section not found")))
+(defvar Man--last-section nil)
+
+(defun Man-goto-section (section)
+  "Move point to SECTION."
+  (interactive
+   (let* ((default (if (member Man--last-section Man--sections)
+                       Man--last-section
+                     (car Man--sections)))
+          (completion-ignore-case t)
+          (prompt (concat "Go to section (default " default "): "))
+          (chosen (completing-read prompt Man--sections
+                                   nil nil nil nil default)))
+     (list chosen)))
+  (setq Man--last-section section)
+  (unless (Man-find-section section)
+    (error "Section %s not found" section)))
 
 
 (defun Man-goto-see-also-section ()
@@ -1559,11 +1594,13 @@ as \"tcgetp-grp(3V)\", and point is at \"grp(3V)\", we return
            (setq word (current-word))))
       word)))
 
+(defvar Man--last-refpage nil)
+
 (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."
   (interactive
-   (if (not Man-refpages-alist)
+   (if (not Man--refpages)
        (error "There are no references in the current man page")
      (list
       (let* ((default (or
@@ -1576,26 +1613,22 @@ Specify which REFERENCE to use; default is based on word at point."
                                   (substring word 0
                                              (match-beginning 0))
                                 word))
-                            Man-refpages-alist))
-                      (aheadsym Man-refpages-alist)))
+                            Man--refpages))
+                       (if (member Man--last-refpage Man--refpages)
+                           Man--last-refpage
+                         (car Man--refpages))))
             (defaults
               (mapcar 'substring-no-properties
-                      (delete-dups
-                       (delq nil (cons default
-                                       (mapcar 'car Man-refpages-alist))))))
-            chosen
-            (prompt (concat "Refer to (default " default "): ")))
-       (setq chosen (completing-read prompt Man-refpages-alist
-                                     nil nil nil nil defaults))
-       (if (or (not chosen)
-               (string= chosen ""))
-           default
-         chosen)))))
-  (if (not Man-refpages-alist)
+                       (cons default Man--refpages)))
+            (prompt (concat "Refer to (default " default "): "))
+            (chosen (completing-read prompt Man--refpages
+                                     nil nil nil nil defaults)))
+        chosen))))
+  (if (not Man--refpages)
       (error "Can't find any references in the current manpage")
-    (aput 'Man-refpages-alist reference)
+    (setq Man--last-refpage reference)
     (Man-getpage-in-background
-     (Man-translate-references (aheadsym Man-refpages-alist)))))
+     (Man-translate-references reference))))
 
 (defun Man-kill ()
   "Kill the buffer containing the manpage."
@@ -1621,7 +1654,7 @@ Specify which REFERENCE to use; default is based on word at point."
   (when Man-page-list
     (if (or (< page 1)
            (> page (length Man-page-list)))
-       (error "No manpage %d found" page))
+       (user-error "No manpage %d found" page))
     (let* ((page-range (nth (1- page) Man-page-list))
           (page-start (car page-range))
           (page-end (car (cdr page-range))))
@@ -1714,9 +1747,6 @@ Uses `Man-name-local-regexp'."
 ;; Init the man package variables, if not already done.
 (Man-init-defvars)
 
-(add-to-list 'debug-ignored-errors "^No manpage [0-9]* found$")
-(add-to-list 'debug-ignored-errors "^Can't find the .* manpage$")
-
 (provide 'man)
 
 ;;; man.el ends here