* bookmark.el (bookmark-buffer-file-name): Abbreviate the bookmark path.
[bpt/emacs.git] / lisp / woman.el
index 5e8aff7..f880c68 100644 (file)
@@ -1,6 +1,7 @@
 ;;; woman.el --- browse UN*X manual pages `wo (without) man'
 
-;; Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
+;;   2006 Free Software Foundation, Inc.
 
 ;; Author: Francis J. Wright <F.J.Wright@qmul.ac.uk>
 ;; Maintainer: FSF
 ;; code fragments, general interest, etc.:
 ;;   Jari Aalto <jari.aalto@cs.tpu.fi>
 ;;   Dean Andrews <dean@dra.com>
-;;   Juanma Barranquero <barranquero@laley-actualidad.es>
+;;   Juanma Barranquero <lekktu@gmail.com>
 ;;   Karl Berry <kb@cs.umb.edu>
 ;;   Jim Chapman <jchapman@netcomuk.co.uk>
 ;;   Kin Cho <kin@neoscale.com>
 
 (require 'man)
 (require 'button)
-(define-button-type 'WoMan-xref-man-page 
+(define-button-type 'WoMan-xref-man-page
   :supertype 'Man-abstract-xref-man-page
-  'func 'woman)
+  'func (lambda (arg)
+         (woman
+          ;; `woman' cannot deal with arguments that contain a
+          ;; section name, like close(2), so strip the section name.
+          (if (string-match Man-reference-regexp arg)
+              (substring arg 0 (match-end 1))
+            arg))))
 
 (eval-when-compile                     ; to avoid compiler warnings
   (require 'dired)
+  (require 'cl)
   (require 'apropos))
 
 (defun woman-mapcan (fn x)
@@ -1189,7 +1197,7 @@ It is saved to the file named by the variable `woman-cache-filename'."
          (kill-buffer standard-output)
          ))))
 
-(defvar woman-topic-history nil "Topic read history.")
+(defvaralias 'woman-topic-history 'Man-topic-history)
 (defvar woman-file-history nil "File-name read history.")
 
 (defun woman-file-name (topic &optional re-cache)
@@ -1743,7 +1751,18 @@ Leave point at end of new text.  Return length of inserted text."
   (define-key woman-mode-map [M-mouse-2] 'woman-follow-word)
 
   ;; We don't need to call `man' when we are in `woman-mode'.
-  (define-key woman-mode-map [remap man] 'woman))
+  (define-key woman-mode-map [remap man] 'woman)
+  (define-key woman-mode-map [remap man-follow] 'woman-follow))
+
+(defun woman-follow (topic)
+  "Get a Un*x manual page of the item under point and put it in a buffer."
+  (interactive (list (Man-default-man-entry)))
+  (if (or (not topic)
+         (string= topic ""))
+      (error "No item under point")
+    (woman (if (string-match Man-reference-regexp topic)
+              (substring topic 0 (match-end 1))
+            topic))))
 
 (defun woman-follow-word (event)
   "Run WoMan with word under mouse as topic.
@@ -2083,6 +2102,18 @@ No external programs are used."
   (interactive)                                ; mainly for testing
   (WoMan-log-begin)
   (run-hooks 'woman-pre-format-hook)
+
+  ;; look for macro sets that woman cannot handle:
+  (goto-char (point-min))
+  (let ((case-fold-search nil))
+    (unless (and (re-search-forward "^\\.SH[ \n]" (point-max) t)
+                (progn (goto-char (point-min))
+                       (re-search-forward "^\\.TH[ \n]" (point-max) t))
+                (progn (goto-char (point-min))
+                       (not (re-search-forward "^\\.\\([pnil]p\\|sh\\)[ \n]"
+                                               (point-max) t))))
+      (error "WoMan can only format man pages written with the usual `-man' macros")))
+
   (and (boundp 'font-lock-mode) font-lock-mode (font-lock-mode -1))
   ;; (fundamental-mode)
   (let ((start-time (current-time))    ; (HIGH LOW MICROSEC)
@@ -2449,6 +2480,7 @@ Start at FROM and re-scan new text as appropriate."
        (woman0-search-regex
         (concat woman0-search-regex-start woman0-search-regex-end))
        woman0-rename-alist)
+    (set-marker-insertion-type woman0-if-to t)
     (while (re-search-forward woman0-search-regex nil t)
       (setq request (match-string 1))
       (cond ((string= request "ig") (woman0-ig))
@@ -2522,7 +2554,7 @@ REQUEST is the invoking directive without the leading dot."
        ;; String delimiter can be any non-numeric character,
        ;; including a special character escape:
        (looking-at "\\(\\\\(..\\|[^0-9]\\)\\(.*\\)\\1\\(.*\\)\\1\\'"))
-      (let ((end1 (copy-marker (match-end 2))))        ; end of first string
+      (let ((end1 (copy-marker (match-end 2) t))) ; End of first string.
        ;; Delete 2nd and 3rd delimiters to avoid processing them:
        (delete-region (match-end 3) woman0-if-to)
        (delete-region (match-end 2) (match-beginning 3))
@@ -2637,10 +2669,9 @@ If DELETE is non-nil then delete from point."
        (error "File `%s' not found" name))
     (beginning-of-line)
     (woman-delete-line 1)
-    (let ((from (point))
-         (to (make-marker))
-         (length (woman-insert-file-contents filename 0)))
-      (set-marker to (+ from length))
+    (let* ((from (point))
+           (length (woman-insert-file-contents filename 0))
+           (to (copy-marker (+ from length) t)))
       (woman-pre-process-region from to)
       (set-marker to nil)
       (goto-char from)
@@ -3424,9 +3455,7 @@ Also bound locally in `woman2-roff-buffer'.")
 (defsubst woman2-process-escapes-to-eol (&optional numeric)
   "Process remaining escape sequences up to eol.
 Handle numeric arguments specially if optional argument NUMERIC is non-nil."
-  (woman2-process-escapes
-   (save-excursion (end-of-line) (point-marker))
-   numeric))
+  (woman2-process-escapes (copy-marker (line-end-position) t) numeric))
 
 (defun woman2-nr (to)
   ".nr R +/-N M -- Assign +/-N (wrt to previous value, if any) to register R.
@@ -3627,6 +3656,7 @@ expression in parentheses.  Leaves point after the value."
        (woman-registers woman-registers)
        fn request translations
        tab-stop-list)
+    (set-marker-insertion-type to t)
     ;; ?roff does not squeeze multiple spaces, but does fill, so...
     (fset 'canonically-space-region 'ignore)
     ;; Try to avoid spaces inheriting underlines from preceding text!
@@ -3669,7 +3699,8 @@ expression in parentheses.  Leaves point after the value."
            ;; Call the appropriate function:
            (funcall fn to)))
       (if (not (eobp))                 ; This should not happen, but ...
-         (woman2-format-paragraphs (point-max-marker) woman-left-margin))
+         (woman2-format-paragraphs (copy-marker (point-max) t)
+                                    woman-left-margin))
       (fset 'canonically-space-region canonically-space-region)
       (fset 'set-text-properties set-text-properties)
       (fset 'insert-and-inherit insert-and-inherit)
@@ -3881,6 +3912,7 @@ Leave 1 blank line.  Format paragraphs upto TO."
 (defun woman2-process-escapes (to &optional numeric)
   "Process remaining escape sequences up to marker TO, preserving point.
 Optional argument NUMERIC, if non-nil, means the argument is numeric."
+  (assert (and (markerp to) (marker-insertion-type to)))
   ;; The first two cases below could be merged (maybe)!
   (let ((from (point)))
     ;; Discard zero width filler character used to hide leading dots
@@ -3950,15 +3982,13 @@ Optional argument NUMERIC, if non-nil, means the argument is numeric."
   (delete-char -1)
   (delete-char 1)
   (looking-at "\\(.\\)\\(.*\\)\\1")
-  (let ((to (make-marker)) from N c)
-    (set-marker to (match-end 2))
-    (delete-char 1)
-    (setq from (point)
-         N (woman-parse-numeric-arg))
-    (setq c (if (< (point) to) (following-char) ?_))
+  (forward-char 1)
+  (let* ((to (match-end 2))
+         (from (match-beginning 0))
+         (N (woman-parse-numeric-arg))
+         (c (if (< (point) to) (following-char) ?_)))
     (delete-region from to)
     (delete-char 1)
-    (set-marker to nil)
     (insert (make-string N c))
     ))
 
@@ -4103,7 +4133,11 @@ If `woman-nofill' is non-nil then indent without filling or adjusting."
               (eolp)
               (skip-syntax-forward " ")
               (setq woman-leave-blank-lines 1))
-         (beginning-of-line)
+         ;; This shouldn't happen, but in case it does (e.g. for
+         ;; badly-formatted manfiles with no terminating newline),
+         ;; avoid an infinite loop.
+         (unless (and (eolp) (eobp))
+           (beginning-of-line))
          ;; If a single short line then just leave it.
          ;; This is necessary to preserve some table layouts.
          ;; PROBABLY NOT NECESSARY WITH SQUEEZE MODIFICATION !!!!!