;;; man.el --- browse UNIX manual pages -*- coding: iso-8859-1 -*-
-;; Copyright (C) 1993, 1994, 1996, 1997, 2001, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1996, 1997, 2001, 2003, 2004
+;; Free Software Foundation, Inc.
;; Author: Barry A. Warsaw <bwarsaw@cen.com>
;; Maintainer: FSF
\f
;;; Code:
+(eval-when-compile (require 'cl))
(require 'assoc)
(require 'button)
:type 'face
:group 'man)
+(defcustom Man-reverse-face 'highlight
+ "*Face to use when fontifying reverse video."
+ :type 'face
+ :group 'man)
+
;; Use the value of the obsolete user option Man-notify, if set.
(defcustom Man-notify-method (if (boundp 'Man-notify) Man-notify 'friendly)
"*Selects the behavior when manpage is ready.
(const polite) (const quiet) (const meek))
:group 'man)
+(defcustom Man-width nil
+ "*Number of columns for which manual pages should be formatted.
+If nil, the width of the window selected at the moment of man
+invocation is used. If non-nil, the width of the frame selected
+at the moment of man invocation is used. The value also can be a
+positive integer."
+ :type '(choice (const :tag "Window width" nil)
+ (const :tag "Frame width" t)
+ (integer :tag "Specific width" :value 65))
+ :group 'man)
+
(defcustom Man-frame-parameters nil
"*Frame parameter list for creating a new frame for a manual page."
:type 'sexp
(defvar Man-cooked-hook nil
"Hook run after removing backspaces but before `Man-mode' processing.")
-(defvar Man-name-regexp "[-a-zA-Z0-9_][-a-zA-Z0-9_.]*"
+(defvar Man-name-regexp "[-a-zA-Z0-9_+][-a-zA-Z0-9_.+]*"
"Regular expression describing the name of a manpage (without section).")
(defvar Man-section-regexp "[0-9][a-zA-Z+]*\\|[LNln]"
"")
"Option that indicates a specified a manual section name.")
+(defvar Man-support-local-filenames 'auto-detect
+ "Internal cache for the value of the function `Man-support-local-filenames'.
+`auto-detect' means the value is not yet determined.
+Otherwise, the value is whatever the function
+`Man-support-local-filenames' should return.")
+
;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;; end user variables
\f
(view-file f)
(error "Cannot read a file: %s" f))
(error "Cannot find a file: %s" f))))
- 'help-echo "mouse-2: mouse-2: display this file")
+ 'help-echo "mouse-2: display this file")
\f
;; ======================================================================
(cond
(Man-fontify-manpage-flag
nil)
- ((= 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
+ ((eq 0 (call-process Man-sed-command nil nil nil Man-sysv-sed-script))
Man-sysv-sed-script)
- ((= 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
+ ((eq 0 (call-process Man-sed-command nil nil nil Man-berkeley-sed-script))
Man-berkeley-sed-script)
(t
nil))))
(defsubst Man-build-man-command ()
"Builds the entire background manpage and cleaning command."
(let ((command (concat manual-program " " Man-switches
- ; Stock MS-DOS shells cannot redirect stderr;
- ; `call-process' below sends it to /dev/null,
- ; so we don't need `2>' even with DOS shells
- ; which do support stderr redirection.
- (if (not (fboundp 'start-process))
- " %s"
- (concat " %s 2>" null-device))))
+ (cond
+ ;; Already has %s
+ ((string-match "%s" manual-program) "")
+ ;; Stock MS-DOS shells cannot redirect stderr;
+ ;; `call-process' below sends it to /dev/null,
+ ;; so we don't need `2>' even with DOS shells
+ ;; which do support stderr redirection.
+ ((not (fboundp 'start-process)) " %s")
+ ((concat " %s 2>" null-device)))))
(flist Man-filter-list))
(while (and flist (car flist))
(let ((pcom (car (car flist)))
(error "Malformed Man-filter-list"))
phrase)
pargs " ")))
- (setq flist (cdr flist))))
+ (setq flist (cdr flist))))
command))
+
+(defun Man-translate-cleanup (string)
+ "Strip leading, trailing and middle spaces."
+ (when (stringp string)
+ ;; Strip leading and trailing
+ (if (string-match "^[ \t\f\r\n]*\\(.+[^ \t\f\r\n]\\)" string)
+ (setq string (match-string 1 string)))
+ ;; middle spaces
+ (setq string (replace-regexp-in-string "[\t\r\n]" " " string))
+ (setq string (replace-regexp-in-string " +" " " string))
+ string))
+
(defun Man-translate-references (ref)
"Translates REF from \"chmod(2V)\" to \"2v chmod\" style.
Leave it as is if already in that style. Possibly downcase and
translate the section (see the Man-downcase-section-letters-flag
and the Man-section-translations-alist variables)."
(let ((name "")
- (section "")
- (slist Man-section-translations-alist))
+ (section "")
+ (slist Man-section-translations-alist))
+ (setq ref (Man-translate-cleanup ref))
(cond
;; "chmod(2V)" case ?
((string-match (concat "^" Man-reference-regexp "$") ref)
slist nil))))
(concat Man-specified-section-option section " " name))))
+(defun Man-support-local-filenames ()
+ "Check the availability of `-l' option of the man command.
+This option allows `man' to interpret command line arguments
+as local filenames.
+Return the value of the variable `Man-support-local-filenames'
+if it was set to nil or t before the call of this function.
+If t, the man command supports `-l' option. If nil, it don't.
+Otherwise, if the value of `Man-support-local-filenames'
+is neither t nor nil, then determine a new value, set it
+to the variable `Man-support-local-filenames' and return
+a new value."
+ (if (or (not Man-support-local-filenames)
+ (eq Man-support-local-filenames t))
+ Man-support-local-filenames
+ (setq Man-support-local-filenames
+ (with-temp-buffer
+ (and (equal (condition-case nil
+ (call-process manual-program nil t nil "--help")
+ (error nil))
+ 0)
+ (progn
+ (goto-char (point-min))
+ (search-forward "--local-file" nil t))
+ t)))))
+
\f
;; ======================================================================
;; default man entry: get word under point
(skip-chars-backward "-a-zA-Z0-9._+:")
(let ((start (point)))
(skip-chars-forward "-a-zA-Z0-9._+:")
- (setq word (buffer-substring start (point))))
+ (setq word (buffer-substring-no-properties start (point))))
(if (string-match "[._]+$" word)
(setq word (substring word 0 (match-beginning 0))))
+ ;; If looking at something like *strcat(... , remove the '*'
+ (if (string-match "^*" word)
+ (setq word (substring word 1)))
;; If looking at something like ioctl(2) or brc(1M), include the
;; section number in the returned value. Remove text properties.
- (forward-word 1)
- ;; Use `format' here to clear any text props from `word'.
- (format "%s%s"
- word
+ (concat word
(if (looking-at
(concat "[ \t]*([ \t]*\\(" Man-section-regexp "\\)[ \t]*)"))
- (format "(%s)" (match-string 1))
- "")))))
+ (format "(%s)" (match-string-no-properties 1)))))))
\f
;; ======================================================================
;;;###autoload
(defalias 'manual-entry 'man)
+
;;;###autoload
(defun man (man-args)
"Get a Un*x manual page and put it in a buffer.
;; 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)))))
+ (setenv "COLUMNS" (number-to-string
+ (cond
+ ((and (integerp Man-width) (> Man-width 0))
+ Man-width)
+ (Man-width (frame-width))
+ ((window-width)))))))
(setenv "GROFF_NO_SGR" "1")
(if (fboundp 'start-process)
(set-process-sentinel
- (start-process manual-program buffer "sh" "-c"
+ (start-process manual-program buffer
+ (if (memq system-type '(cygwin windows-nt))
+ shell-file-name
+ "sh")
+ shell-command-switch
(format (Man-build-man-command) man-args))
'Man-bgproc-sentinel)
(let ((exit-status
- (call-process shell-file-name nil (list buffer nil) nil "-c"
+ (call-process shell-file-name nil (list buffer nil) nil
+ shell-command-switch
(format (Man-build-man-command) man-args)))
(msg ""))
(or (and (numberp exit-status)
"Convert overstriking and underlining to the correct fonts.
Same for the ANSI bold and normal escape sequences."
(interactive)
- (message "Please wait: making up the %s man page..." Man-arguments)
+ (message "Please wait: formatting the %s man page..." Man-arguments)
(goto-char (point-min))
- (while (search-forward "\e[1m" nil t)
- (delete-backward-char 4)
- (put-text-property (point)
- (progn (if (search-forward "\e[0m" nil 'move)
- (delete-backward-char 4))
- (point))
- 'face Man-overstrike-face))
+ ;; Fontify ANSI escapes.
+ (let ((faces nil)
+ (start (point)))
+ ;; http://www.isthe.com/chongo/tech/comp/ansi_escapes.html
+ ;; suggests many codes, but we only handle:
+ ;; ESC [ 00 m reset to normal display
+ ;; ESC [ 01 m bold
+ ;; ESC [ 04 m underline
+ ;; ESC [ 07 m reverse-video
+ ;; ESC [ 22 m no-bold
+ ;; ESC [ 24 m no-underline
+ ;; ESC [ 27 m no-reverse-video
+ (while (re-search-forward "\e\\[0?\\([1470]\\|2\\([247]\\)\\)m" nil t)
+ (if faces (put-text-property start (match-beginning 0) 'face
+ (if (cdr faces) faces (car faces))))
+ (setq faces
+ (cond
+ ((match-beginning 2)
+ (delq (case (char-after (match-beginning 2))
+ (?2 Man-overstrike-face)
+ (?4 Man-underline-face)
+ (?7 Man-reverse-face))
+ faces))
+ ((eq (char-after (match-beginning 1)) ?0) nil)
+ (t
+ (cons (case (char-after (match-beginning 1))
+ (?1 Man-overstrike-face)
+ (?4 Man-underline-face)
+ (?7 Man-reverse-face))
+ faces))))
+ (delete-region (match-beginning 0) (match-end 0))
+ (setq start (point))))
+ ;; Other highlighting.
(if (< (buffer-size) (position-bytes (point-max)))
;; Multibyte characters exist.
(progn
;; Try to recognize common forms of cross references.
(Man-highlight-references)
(Man-softhyphen-to-minus)
- (message "%s man page made up" Man-arguments))
+ (goto-char (point-min))
+ (while (re-search-forward Man-heading-regexp nil t)
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'face Man-overstrike-face))
+ (message "%s man page formatted" Man-arguments))
(defun Man-highlight-references ()
"Highlight the references on mouse-over.
'Man-target-string (match-string target-pos)
)))))
-(defun Man-cleanup-manpage ()
- "Remove overstriking and underlining from the current buffer."
- (interactive)
+(defun Man-cleanup-manpage (&optional interactive)
+ "Remove overstriking and underlining from the current buffer.
+Normally skip any jobs that should have been done by the sed script,
+but when called interactively, do those jobs even if the sed
+script would have done them."
+ (interactive "p")
(message "Please wait: cleaning up the %s man page..."
Man-arguments)
- (if (or (interactive-p) (not Man-sed-script))
+ (if (or interactive (not Man-sed-script))
(progn
(goto-char (point-min))
(while (search-forward "_\b" nil t) (backward-delete-char 2))
(auto-fill-mode -1)
(use-local-map Man-mode-map)
(set-syntax-table man-mode-syntax-table)
+ (setq imenu-generic-expression (list (list nil Man-heading-regexp 0)))
+ (set (make-local-variable 'outline-regexp) Man-heading-regexp)
+ (set (make-local-variable 'outline-level) (lambda () 1))
(Man-build-page-list)
(Man-strip-page-headers)
(Man-unindent)
(provide 'man)
+;; arch-tag: 587cda76-8e23-4594-b1f3-89b6b09a0d47
;;; man.el ends here