;;; woman.el --- browse UN*X manual pages `wo (without) man'
-;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
-;; 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+;; 2009, 2010, 2011 Free Software Foundation, Inc.
;; Author: Francis J. Wright <F.J.Wright@qmul.ac.uk>
;; Maintainer: FSF
;; Keywords: help, unix
;; Adapted-By: Eli Zaretskii <eliz@gnu.org>
-;; Version: see `woman-version'
+;; Version: 0.551
;; URL: http://centaur.maths.qmul.ac.uk/Emacs/WoMan/
;; This file is part of GNU Emacs.
(parse-colon-path paths)))
((string-match "\\`[a-zA-Z]:" paths)
;; Assume single DOS-style path...
- paths)
+ (list paths))
(t
;; Assume UNIX/Cygwin-style path-list...
(woman-mapcan ; splice list into list
(defvar woman-file-regexp nil
"Regexp used to select (possibly compressed) man source files, e.g.
-\"\\.\\([0-9lmnt]\\w*\\)\\(\\.\\(g?z\\|bz2\\)\\)?\\'\".
+\"\\.\\([0-9lmnt]\\w*\\)\\(\\.\\(g?z\\|bz2\\|xz\\)\\)?\\'\".
Built automatically from the customizable user options
`woman-uncompressed-file-regexp' and `woman-file-compression-regexp'.")
:group 'woman-interface)
(defcustom woman-file-compression-regexp
- "\\.\\(g?z\\|bz2\\)\\'"
+ "\\.\\(g?z\\|bz2\\|xz\\)\\'"
"Do not change this unless you are sure you know what you are doing!
Regexp used to match compressed man file extensions for which
decompressors are available and handled by auto-compression mode,
-e.g. \"\\\\.\\\\(g?z\\\\|bz2\\\\)\\\\'\" for `gzip' or `bzip2'.
+e.g. \"\\\\.\\\\(g?z\\\\|bz2\\\\|xz\\\\)\\\\'\" for `gzip', `bzip2', or `xz'.
Should begin with \\. and end with \\' and MUST NOT be optional."
;; Should be compatible with car of
;; `jka-compr-file-name-handler-entry', but that is unduly
;; complicated, includes an inappropriate extension (.tgz) and is
;; not loaded by default!
+ :version "24.1" ; added xz
:type 'regexp
:set 'set-woman-file-regexp
:group 'woman-interface)
-(defcustom woman-use-own-frame ; window-system
- (or (and (fboundp 'display-graphic-p) (display-graphic-p)) ; Emacs 21
- (memq window-system '(x w32 ns))) ; Emacs 20
+(defcustom woman-use-own-frame nil
"If non-nil then use a dedicated frame for displaying WoMan windows.
Only useful when run on a graphic display such as X or MS-Windows."
:type 'boolean
:type 'boolean
:group 'woman-faces)
-;; This is overkill! Troff uses just italic; Nroff uses just underline.
-;; You should probably select either italic or underline as you prefer, but
-;; not both, although italic and underline work together perfectly well!
(defface woman-italic
- `((((min-colors 88) (background light))
- (:slant italic :underline t :foreground "red1"))
- (((background light)) (:slant italic :underline t :foreground "red"))
- (((background dark)) (:slant italic :underline t)))
+ '((t :inherit italic))
"Face for italic font in man pages."
:group 'woman-faces)
-;; backward-compatibility alias
-(put 'woman-italic-face 'face-alias 'woman-italic)
+(define-obsolete-face-alias 'woman-italic-face 'woman-italic "22.1")
(defface woman-bold
- '((((min-colors 88) (background light)) (:weight bold :foreground "blue1"))
- (((background light)) (:weight bold :foreground "blue"))
- (((background dark)) (:weight bold :foreground "green2")))
+ '((t :inherit bold))
"Face for bold font in man pages."
:group 'woman-faces)
-;; backward-compatibility alias
-(put 'woman-bold-face 'face-alias 'woman-bold)
+(define-obsolete-face-alias 'woman-bold-face 'woman-bold "22.1")
-;; Brown is a good compromise: it is distinguishable from the default
-;; but not enough so to make font errors look terrible. (Files that use
-;; non-standard fonts seem to do so badly or in idiosyncratic ways!)
(defface woman-unknown
- '((((background light)) (:foreground "brown"))
- (((min-colors 88) (background dark)) (:foreground "cyan1"))
- (((background dark)) (:foreground "cyan")))
+ '((t :inherit font-lock-warning-face))
"Face for all unknown fonts in man pages."
:group 'woman-faces)
-;; backward-compatibility alias
-(put 'woman-unknown-face 'face-alias 'woman-unknown)
+(define-obsolete-face-alias 'woman-unknown-face 'woman-unknown "22.1")
(defface woman-addition
- '((t (:foreground "orange")))
+ '((t :inherit font-lock-builtin-face))
"Face for all WoMan additions to man pages."
:group 'woman-faces)
-;; backward-compatibility alias
-(put 'woman-addition-face 'face-alias 'woman-addition)
+(define-obsolete-face-alias 'woman-addition-face 'woman-addition "22.1")
(defun woman-default-faces ()
"Set foreground colors of italic and bold faces to their default values."
(woman-find-file file-name)
(message
"WoMan Error: No matching manual files found in search path")
- (ding))
- )
+ (ding)))
(message "WoMan Error: No topic specified in non-interactive call")
- (ding))
- )
+ (ding)))
;; Allow WoMan to be called via the standard Help menu:
(define-key-after menu-bar-manuals-menu [woman]
be found. Optional argument RE-CACHE, if non-nil, forces the
cache to be re-read."
;; Handle the caching of the directory and topic lists:
- (if (and (not re-cache)
- (or
- (and woman-expanded-directory-path woman-topic-all-completions)
- (woman-read-directory-cache)))
- ()
+ (unless (and (not re-cache)
+ (or
+ (and woman-expanded-directory-path woman-topic-all-completions)
+ (woman-read-directory-cache)))
(message "Building list of manual directory expansions...")
(setq woman-expanded-directory-path
(woman-expand-directory-path woman-manpath woman-path))
'woman-topic-history
default))))
;; Note that completing-read always returns a string.
- (if (= (length topic) 0)
- nil ; no topic, so no file!
+ (unless (= (length topic) 0)
(cond
((setq files (woman-file-name-all-completions topic)))
;; Complete topic more carefully, i.e. use the completion
(not (member (car cdr_list) (cdr cdr_list)))
(funcall predicate (car cdr_list)))
(setq list cdr_list)
- (setcdr list (cdr cdr_list)))
- )
+ (setcdr list (cdr cdr_list))))
newlist)))
(defun woman-file-readable-p (dir)
;; (topic)
;; (topic (path-index) (path-index) ... )
;; (topic (path-index filename) (path-index filename) ... )
- ;; where the are no duplicates in the value lists.
+ ;; where there are no duplicates in the value lists.
;; Topic must match first `word' of filename, so ...
(let ((topic-regexp
(concat
path (cdr path))
(if (woman-not-member dir path) ; use each directory only once!
(setq files (nconc files
- (directory-files dir t topic-regexp))))
- ))
- (mapcar 'list files)
- ))
+ (directory-files dir t topic-regexp))))))
+ (mapcar 'list files)))
\f
;;; dired support
(or exists
(setq woman-buffer-alist
(cons (cons file-name bufname) woman-buffer-alist)
- woman-buffer-number 0))
- )))
+ woman-buffer-number 0)))))
(Man-build-section-alist)
(Man-build-references-alist)
(goto-char (point-min)))
(defun woman-make-bufname (bufname)
"Create an unambiguous buffer name from BUFNAME."
- (let ((dot (string-match "\\." bufname)))
+ ;; See Bug#5038. Any compression extension has already been removed.
+ ;; Go from eg "host.conf.5" to "5 host.conf".
+ (let ((dot (string-match "\\.[^.]*\\'" bufname)))
(if dot (setq bufname (concat
(substring bufname (1+ dot)) " "
(substring bufname 0 dot))))
(goto-char (point-min))
(forward-line)
(while (re-search-forward "^\\( \\)?\\([A-Z].*\\)" nil t)
- (woman-set-face (match-beginning 2) (match-end 2) 'woman-bold))))
- )
+ (woman-set-face (match-beginning 2) (match-end 2) 'woman-bold)))))
(defun woman-insert-file-contents (filename compressed)
"Insert file FILENAME into the current buffer.
(file-error
;; Run find-file-not-found-hooks until one returns non-nil.
;; (run-hook-with-args-until-success 'find-file-not-found-hooks)
- (insert "\n***** File " filename " not found! *****\n\n")
- )))
- )))
+ (insert "\n***** File " filename " not found! *****\n\n")))))))
\f
;;; Major mode (Man) interface:
(setq woman-emulation value)
(woman-reformat-last-file))
+(defvar bookmark-make-record-function)
(put 'woman-mode 'mode-class 'special)
(defun woman-mode ()
(fset 'Man-build-page-list Man-build-page-list)
(fset 'Man-strip-page-headers Man-strip-page-headers)
(fset 'Man-unindent Man-unindent)
- (fset 'Man-goto-page Man-goto-page)))
+ (fset 'Man-goto-page Man-goto-page)
+ (setq tab-width woman-tab-width)))
(setq major-mode 'woman-mode
mode-name "WoMan")
;; Don't show page numbers like Man-mode does. (Online documents do
;; `make-local-variable' in case imenu not yet loaded!
woman-imenu-generic-expression)
(set (make-local-variable 'imenu-space-replacement) " ")
+ ;; Bookmark support.
+ (set (make-local-variable 'bookmark-make-record-function)
+ 'woman-bookmark-make-record)
;; For reformat ...
;; necessary when reformatting a file in its old buffer:
(setq imenu--last-menubar-index-alist nil)
(interactive)
(setq woman-fill-frame (not woman-fill-frame))
(message "Woman fill column set to %s."
- (if woman-fill-frame "frame width" woman-fill-column)
- ))
+ (if woman-fill-frame "frame width" woman-fill-column)))
(defun woman-mini-help ()
"Display WoMan commands and user options in an `apropos' buffer."
(require 'apropos)
(let ((message
(let ((standard-output (get-buffer-create "*Apropos*")))
- (print-help-return-message 'identity))))
+ (help-print-return-message 'identity))))
(setq apropos-accumulator
(apropos-internal "woman"
(lambda (symbol)
(setcdr prev-ptr (cdr (cdr prev-ptr)))
(if (>= woman-buffer-number (length woman-buffer-alist))
(setq woman-buffer-number 0))
- nil)
- )))
+ nil))))
\f
;;; Syntax and display tables:
(woman-delete-match 0)
(WoMan-warn
"Terminal vertical motion escape \\%s ignored!" esc)))
- (setq first (not first))
- )))
-
-; ;; \h'+/-N' local horizontal motion.
-; ;; N may include width escape \w'...'
-; ;; Implement arbitrary forward motion and non-overlapping backward
-; ;; motion.
-; (goto-char from)
-; (while (re-search-forward
-; ;; Delimiter can be a special char escape sequence \(.. or
-; ;; a single normal char (usually '):
-; "\\\\h\\(\\\\(..\\|.\\)\\(|\\)?"
-; nil t)
-; (let ((from (match-beginning 0))
-; (delim (regexp-quote (match-string 1)))
-; (absolute (match-string 2)) ; absolute position?
-; (N (woman-parse-numeric-arg)) ; distance
-; to
-; msg) ; for warning
-; (if (not (looking-at delim))
-; ;; Warn but leave escape in buffer unprocessed:
-; (WoMan-warn
-; "Local horizontal motion (%s) delimiter error!"
-; (buffer-substring from (1+ (point)))) ; point at end of arg
-; (setq to (match-end 0)
-; ;; For possible warning -- save before deleting:
-; msg (buffer-substring from to))
-; (delete-region from to)
-; (if absolute ; make relative
-; (setq N (- N (current-column))))
-; (if (>= N 0)
-; ;; Move forward by inserting hard spaces:
-; (insert-char woman-unpadded-space-char N)
-; ;; Move backwards by deleting space,
-; ;; first backwards then forwards:
-; (while (and
-; (<= (setq N (1+ N)) 0)
-; (cond ((memq (preceding-char) '(?\ ?\t))
-; (delete-backward-char 1) t)
-; ((memq (following-char) '(?\ ?\t))
-; (delete-char 1) t)
-; (t nil))))
-; (if (<= N 0)
-; (WoMan-warn
-; "Negative horizontal motion (%s) would overwrite!" msg))))
-; ))
+ (setq first (not first)))))
;; Process formatting macros
(goto-char from)
(delete-char -1) (insert ?\\))
(goto-char from)
(while (search-forward woman-unpadded-space-string nil t)
- (delete-char -1) (insert ?\ ))
- ))
+ (delete-char -1) (insert ?\ ))))
;; Must return the new end of file if used in format-alist.
(point-max)))
(while (and
(<= (setq N (1+ N)) 0)
(cond ((memq (preceding-char) '(?\ ?\t))
- (delete-backward-char 1) t)
+ (delete-char -1) t)
((memq (following-char) '(?\ ?\t))
(delete-char 1) t)
(t nil))))
(if (<= N 0)
(WoMan-warn
- "Negative horizontal motion (%s) would overwrite!" msg))))
- ))
+ "Negative horizontal motion (%s) would overwrite!" msg))))))
(goto-char from)))
Start at FROM and re-scan new text as appropriate."
(goto-char from)
(let ((woman0-if-to (make-marker))
- request woman0-macro-alist
+ woman-request woman0-macro-alist
(woman0-search-regex-start woman0-search-regex-start)
(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))
- ((string= request "if") (woman0-if "if"))
- ((string= request "ie") (woman0-if "ie"))
- ((string= request "el") (woman0-el))
- ((string= request "so") (woman0-so))
- ((string= request "rn") (woman0-rn))
- ((string= request "de") (woman0-de))
- ((string= request "am") (woman0-de 'append))
- (t (woman0-macro request))))
+ (setq woman-request (match-string 1))
+ (cond ((string= woman-request "ig") (woman0-ig))
+ ((string= woman-request "if") (woman0-if "if"))
+ ((string= woman-request "ie") (woman0-if "ie"))
+ ((string= woman-request "el") (woman0-el))
+ ((string= woman-request "so") (woman0-so))
+ ((string= woman-request "rn") (woman0-rn))
+ ((string= woman-request "de") (woman0-de))
+ ((string= woman-request "am") (woman0-de 'append))
+ (t (woman0-macro woman-request))))
(set-marker woman0-if-to nil)
(woman0-rename)
;; Should now re-run `woman0-roff-buffer' if any renaming was
(delete-region from (point))
(WoMan-warn
"ig request ignored -- terminator `.%s' not found!" yy)
- (woman-delete-line 1))
- ))
+ (woman-delete-line 1))))
(defsubst woman0-process-escapes (from to)
"Process escapes within an if/ie condition between FROM and TO."
(goto-char from) ; necessary!
(woman2-process-escapes to 'numeric))
+;; request does not appear to be used dynamically by any callees.
(defun woman0-if (request)
".if/ie c anything -- Discard unless c evaluates to true.
Remember condition for use by a subsequent `.el'.
(woman0-process-escapes from woman0-if-to)
(woman-parse-numeric-arg))))
(setq c (> n 0))
- (goto-char from))
- )
+ (goto-char from)))
(if (eq c 0)
(woman-if-ignore woman0-if-to request) ; ERROR!
- (woman-if-body request woman0-if-to (eq c negated)))
- ))
+ (woman-if-body request woman0-if-to (eq c negated)))))
+;; request is not used dynamically by any callees.
(defun woman-if-body (request to delete) ; should be reversed as `accept'?
"Process if-body, including \\{ ... \\}.
REQUEST is the invoking directive without the leading dot.
(delete-region (if delete from (match-beginning 0)) (point))
(if (looking-at "^$") (delete-char 1))
))
- (delete (woman-delete-line 1)) ; single-line
- )
+ (delete (woman-delete-line 1))) ; single-line
;; Process matching .el anything:
- (cond ((string= request "ie")
+ (cond ((string= request "ie")
;; Discard unless previous .ie c `evaluated to false'.
(cond ((re-search-forward "^[.'][ \t]*el[ \t]*" nil t)
(woman-delete-match 0)
((string= request "el")
(cond ((re-search-forward "^[.'][ \t]*el[ \t]*" nil t)
(woman-delete-match 0)
- (woman-if-body "el" nil t))))
- )
- (goto-char from)
- ))
+ (woman-if-body "el" nil t)))))
+ (goto-char from)))
(defun woman0-el ()
"Isolated .el request -- should not happen!"
(if (looking-at "[ \t]*\\{") (search-forward "\\}"))
(forward-line 1))))
+;; request is not used dynamically by any callees.
(defun woman-if-ignore (to request)
"Ignore but warn about an if request ending at TO, named REQUEST."
(WoMan-warn-ignored request "ignored -- condition not handled!")
(to (copy-marker (+ from length) t)))
(woman-pre-process-region from to)
(set-marker to nil)
- (goto-char from)
- )))
+ (goto-char from))))
\f
;;; Process macro definitions:
(setq beg (point)
end (progn (woman-forward-arg 'unquote) (point))
new (buffer-substring beg end)
- woman0-rename-alist (cons (cons new old) woman0-rename-alist)))
- ))
+ woman0-rename-alist (cons (cons new old) woman0-rename-alist)))))
(woman-delete-whole-line))
(defun woman0-rename ()
(setq woman0-macro-alist (cons macro woman0-macro-alist))
(forward-line)
(delete-region from (point))
- (backward-char) ; return to end of .de/am line
- ))
+ (backward-char))) ; return to end of .de/am line
(beginning-of-line) ; delete .de/am line
(woman-delete-line 1))
-(defun woman0-macro (request)
- "Process the macro call named REQUEST."
+;; request may be used dynamically (woman-interpolate-macro calls
+;; woman-forward-arg).
+(defun woman0-macro (woman-request)
+ "Process the macro call named WOMAN-REQUEST."
;; Leaves point at start of new text.
- (let ((macro (assoc request woman0-macro-alist)))
+ (let ((macro (assoc woman-request woman0-macro-alist)))
(if macro
(woman-interpolate-macro (cdr macro))
;; SHOULD DELETE THE UNINTERPRETED REQUEST!!!!!
;; Output this message once only per call (cf. strings)?
- (WoMan-warn "Undefined macro %s not interpolated!" request))))
+ (WoMan-warn "Undefined macro %s not interpolated!" woman-request))))
(defun woman-interpolate-macro (macro)
"Interpolate (.de) or append (.am) expansion of MACRO into the buffer."
;; Replace formal arg with actual arg:
(setq start nil)
(while (setq start (string-match formal-arg macro start))
- (setq macro (replace-match actual-arg t t macro)))
- )
+ (setq macro (replace-match actual-arg t t macro))))
;; Delete any remaining formal arguments:
(setq start nil)
(while
(delete-region beg (point))
(setq woman-string-alist
(cons (cons stringname "")
- woman-string-alist))))
- ))
- ))
- ))
- ))
+ woman-string-alist))))))))))))
\f
;;; Process special character escapes \(xx:
(WoMan-warn (concat "Special character "
(if (match-beginning 1) "\\(%s" "\\[%s]")
" not interpolated!") name)
- (if woman-ignore (woman-delete-match 0))))
- ))
+ (if woman-ignore (woman-delete-match 0))))))
(defun woman-display-extended-fonts ()
"Display table of glyphs of graphic characters and their octal codes.
(insert " ")
(setq i (1+ i))
(when (= i 128) (setq i 160) (insert "\n"))
- (if (zerop (% i 8)) (insert "\n")))
- ))
- (print-help-return-message)))
+ (if (zerop (% i 8)) (insert "\n")))))
+ (help-print-return-message)))
\f
;;; Formatting macros that do not cause a break:
-(defvar request) ; Bound locally by woman1-roff-buffer
-(defvar unquote) ; Bound locally by woman1-roff-buffer
+;; Bound locally by woman[012]-roff-buffer, and also, annoyingly and
+;; confusingly, as a function argument. Use dynamically in
+;; woman-unquote and woman-forward-arg.
+(defvar woman-request)
(defun woman-unquote (to)
"Delete any double-quote characters between point and TO.
(setq in-quote (not in-quote))
))
(if in-quote
- (WoMan-warn "Unpaired \" in .%s arguments." request))
- ))
+ (WoMan-warn "Unpaired \" in .%s arguments." woman-request))))
(defsubst woman-unquote-args ()
"Delete any double-quote characters up to the end of the line."
(defun woman1-roff-buffer ()
"Process non-breaking requests."
(let ((case-fold-search t)
- request fn unquote)
+ woman-request fn woman1-unquote)
(while
;; Find next control line:
(re-search-forward woman-request-regexp nil t)
;; Construct woman function to call:
((setq fn (intern-soft
(concat "woman1-"
- (setq request (match-string 1)))))
+ (setq woman-request (match-string 1)))))
(if (get fn 'notfont) ; not a font-change request
(funcall fn)
;; Delete request or macro name:
(woman-delete-match 0)
;; If no args then apply to next line else unquote args
- ;; (unquote is used by called function):
- (setq unquote (not (eolp)))
+ ;; (woman1-unquote is used by called function):
+ (setq woman1-unquote (not (eolp)))
(if (eolp) (delete-char 1))
; ;; Hide leading control character in unquoted argument:
; (cond ((memq (following-char) '(?. ?'))
;; Call the appropriate function:
(funcall fn)
;; Hide leading control character in quoted argument (only):
- (if (and unquote (memq (following-char) '(?. ?')))
- (insert "\\&"))
- )
- )))))
+ (if (and woman1-unquote (memq (following-char) '(?. ?')))
+ (insert "\\&"))))))))
;;; Font-changing macros:
".I -- Set words of current line in italic font."
(woman1-B-or-I ".ft I\n"))
+(defvar woman1-unquote) ; bound locally by woman1-roff-buffer
+
(defun woman1-B-or-I (B-or-I)
".B/I -- Set words of current line in bold/italic font.
B-OR-I is the appropriate complete control line."
;; Return to bol to process .SM/.B, .B/.if etc.
;; or start of first arg to hide leading control char.
(save-excursion
- (if unquote
+ (if woman1-unquote
(woman-unquote-args)
(while (looking-at "^[.']") (forward-line))
(end-of-line)
;; Return to start of first arg to hide leading control char:
(save-excursion
(setq fonts (cdr fonts))
- (woman-forward-arg unquote 'concat) ; unquote is bound above
+ ;; woman1-unquote is bound in woman1-roff-buffer.
+ (woman-forward-arg woman1-unquote 'concat)
(while (not (eolp))
(insert (car fonts))
(setq fonts (cdr fonts))
- (woman-forward-arg unquote 'concat)) ; unquote is bound above
- (insert "\\fR")
- ))
+ (woman-forward-arg woman1-unquote 'concat))
+ (insert "\\fR")))
(defun woman-forward-arg (&optional unquote concat)
"Move forward over one ?roff argument, optionally unquoting and/or joining.
(if unquote (delete-char 1) (forward-char))
(re-search-forward "\"\\|$"))
(if (eq (preceding-char) ?\")
- (if unquote (delete-backward-char 1))
- (WoMan-warn "Unpaired \" in .%s arguments." request)
- ))
+ (if unquote (delete-char -1))
+ (WoMan-warn "Unpaired \" in .%s arguments." woman-request)))
;; (re-search-forward "[^\\\n] \\|$") ; inconsistent
(skip-syntax-forward "^ "))
(cond ((null concat) (skip-chars-forward " \t")) ; don't skip eol!
((eq concat 'noskip)) ; do not skip following whitespace
- (t (woman-delete-following-space)))
- )
+ (t (woman-delete-following-space))))
;; The following requests are not explicit font-change requests and
(woman-delete-whole-line)
(insert ".ft I\n")
(forward-line N)
- (insert ".ft R\n")
- ))
+ (insert ".ft R\n")))
;;; Other non-breaking requests:
(save-excursion
(while (and (re-search-forward c nil t)
(match-beginning 1))
- (delete-char -1)))
- ))
+ (delete-char -1)))))
(put 'woman1-hw 'notfont t)
(defun woman1-hw ()
fescape t)
(woman-match-name))
(t (setq notfont t)))
- (if notfont
- ()
+ (unless notfont
;; Get font name:
(or font
(let ((fontstring (match-string 0)))
(setq current-font font)
)))
;; Set font after last request up to eob:
- (woman-set-face previous-pos (point) current-font)
- ))
+ (woman-set-face previous-pos (point) current-font)))
(defun woman-set-face (from to face)
"Set the face of the text from FROM to TO to face FACE.
(put-text-property from (point) 'face face-no-ul)
(setq from (point))
)))
- (put-text-property from to 'face face))
- ))
+ (put-text-property from to 'face face))))
\f
;;; Output translation:
-(defvar translations nil) ; Also bound locally by woman2-roff-buffer
+;; This is only set by woman2-tr. It is bound locally in woman2-roff-buffer.
+;; It is also used by woman-translate. woman-translate may be called
+;; outside the scope of woman2-roff-buffer (by experiment). Therefore
+;; this used to be globally bound to nil, to avoid an error. Instead
+;; we can use bound-and-true-p in woman-translate.
+(defvar woman-translations)
;; A list of the form (\"[ace]\" (a . b) (c . d) (e . ?\ )) or nil.
(defun woman-get-next-char ()
;; This should be an update, but consing onto the front of the alist
;; has the same effect and match duplicates should not matter.
;; Initialize translation data structures:
- (let ((matches (car translations))
- (alist (cdr translations))
+ (let ((matches (car woman-translations))
+ (alist (cdr woman-translations))
a b)
;; `matches' must be a string:
(setq matches
(if (= (string-to-char matches) ?\])
(substring matches 3)
(concat "[" matches))
- translations (cons matches alist))
+ woman-translations (cons matches alist))
;; Format any following text:
- (woman2-format-paragraphs to)
- ))
+ (woman2-format-paragraphs to)))
(defsubst woman-translate (to)
"Translate up to marker TO. Do this last of all transformations."
- (if translations
- (let ((matches (car translations))
- (alist (cdr translations)))
+ (if (bound-and-true-p woman-translations)
+ (let ((matches (car woman-translations))
+ (alist (cdr woman-translations))
+ ;; Translations are case-sensitive, eg ".tr ab" does not
+ ;; affect "A" (bug#6849).
+ (case-fold-search nil))
(while (re-search-forward matches to t)
;; Done like this to retain text properties and
;; support translation of special characters:
(buffer-substring-no-properties
(match-beginning 0) (match-end 0))
alist)))
- (woman-delete-match 0))
- )))
+ (woman-delete-match 0)))))
\f
;;; Registers:
; (WoMan-warn "Unimplemented numerical operator `%c' in %s"
; (following-char)
; (buffer-substring
-; (save-excursion (beginning-of-line) (point))
-; (save-excursion (end-of-line) (point))))
+; (line-beginning-position)
+; (line-end-position)))
; (skip-syntax-forward "^ "))
value
))
(if (re-search-forward delim nil t)
;; Return width of string:
(- (match-beginning 0) from)
- (WoMan-warn "Width escape delimiter error!"))))
- )))
+ (WoMan-warn "Width escape delimiter error!")))))))
(if (null n)
;; ERROR -- should handle this better!
(progn
(WoMan-warn "Numeric/register argument error: %s"
(buffer-substring
(point)
- (save-excursion (end-of-line) (point))))
+ (line-end-position)))
(skip-syntax-forward "^ ")
0)
(goto-char (match-end 0))
;; in which case do nothing and return nil.
)
(goto-char (match-end 0)))
- (if (numberp n) (round n) n))
- )))
+ (if (numberp n) (round n) n)))))
\f
;;; VERTICAL FORMATTING -- Formatting macros that cause a break:
(insert-and-inherit (symbol-function 'insert-and-inherit))
(set-text-properties (symbol-function 'set-text-properties))
(woman-registers woman-registers)
- fn request translations
+ fn woman-request woman-translations
tab-stop-list)
(set-marker-insertion-type to t)
;; ?roff does not squeeze multiple spaces, but does fill, so...
;; Construct woman function to call:
((setq fn (intern-soft
(concat "woman2-"
- (setq request (match-string 1)))))
+ (setq woman-request (match-string 1)))))
;; Delete request or macro name:
(woman-delete-match 0))
;; Unrecognised request:
((prog1 nil
- ;; (WoMan-warn ".%s request ignored!" request)
- (WoMan-warn-ignored request "ignored!")
+ ;; (WoMan-warn ".%s request ignored!" woman-request)
+ (WoMan-warn-ignored woman-request "ignored!")
;; (setq fn 'woman2-LP)
;; AVOID LEAVING A BLANK LINE!
;; (setq fn 'woman2-format-paragraphs)
(defsubst woman-interparagraph-space ()
"Set variable `woman-leave-blank-lines' from `woman-interparagraph-distance'."
-; (if (> woman-interparagraph-distance 0)
-; (forward-line 1) ; leave 1 blank line
-; (woman-delete-line 1)) ; do not leave blank line
- (setq woman-leave-blank-lines woman-interparagraph-distance)
- )
+ (setq woman-leave-blank-lines woman-interparagraph-distance))
(defun woman2-TH (to)
".TH n c x v m -- Begin a man page. Format paragraphs upto TO.
(let ((start (point)) here)
(while (not (eolp))
(cond ((looking-at "\"\"[ \t]")
- (delete-char 2)
- ;; (delete-horizontal-space)
- ))
+ (delete-char 2)))
(delete-horizontal-space)
(setq here (point))
(insert " -- ")
(buffer-substring start here))
(delete-region here (point)))))
;; Embolden heading (point is at end of heading):
- (woman-set-face
- (save-excursion (beginning-of-line) (point)) (point) 'woman-bold)
+ (woman-set-face (line-beginning-position) (point) 'woman-bold)
(forward-line)
(delete-blank-lines)
(setq woman-left-margin woman-default-indent)
(setq woman-leave-blank-lines nil)
;; Optionally embolden heading (point is at beginning of heading):
(if woman-bold-headings
- (woman-set-face
- (point) (save-excursion (end-of-line) (point)) 'woman-bold))
+ (woman-set-face (point) (line-end-position) 'woman-bold))
(forward-line)
(setq woman-left-margin woman-default-indent
woman-nofill nil) ; fill output lines
"Character(s) overwritten by negative vertical spacing in line %d"
(count-lines 1 (point))))
(delete-char 1) (insert (substring overlap i (1+ i)))))
- (setq i (1+ i))
- ))
- )))
+ (setq i (1+ i)))))))
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The first two cases below could be merged (maybe)!
(let ((from (point)))
;; Discard zero width filler character used to hide leading dots
- ;; and zero width characters \|, \^:
+ ;; and zero width characters.
(while (re-search-forward "\\\\[&|^]" to t)
- (woman-delete-match 0))
+ (woman-delete-match 0)
+ ;; If on a line by itself, consume newline as well (Bug#3651).
+ (and (eq (char-before (match-beginning 0)) ?\n)
+ (eq (char-after (match-beginning 0)) ?\n)
+ (delete-char 1)))
+
(goto-char from)
;; Interrupt text processing -- CONTINUE current text with the
;; next text line (after any control lines, unless processing to
(delete-char 1)
(insert ?`))))
((eq c ?\( )) ; uninterpreted special character
- ; \(.. -- do nothing
+ ; \(.. -- do nothing
((eq c ?t) ; non-interpreted tab \t
(delete-char 1)
(delete-char -1)
(c (if (< (point) to) (following-char) ?_)))
(delete-region from to)
(delete-char 1)
- (insert (make-string N c))
- ))
+ (insert (make-string N c))))
;;; 4. Text Filling, Adjusting, and Centering
(defun woman2-nf (to)
".nf -- Nofill. Subsequent lines are neither filled nor adjusted.
Input text lines are copied directly to output lines without regard
-for the current line length. Format paragraphs upto TO."
+for the current line length. Format paragraphs up to TO."
(setq woman-nofill t)
(woman-delete-line 1) ; ignore any arguments
(woman2-format-paragraphs to))
(progn (skip-syntax-forward " ")
(beginning-of-line)
(point)))
- (if woman-nospace
- ()
+ (unless woman-nospace
(if (or (null leave) (eq leave 0))
;; output any `pending' vertical space ...
(setq leave woman-leave-blank-lines))
- (if (and leave (> leave 0)) (insert-before-markers ?\n))
- )
- (setq woman-leave-blank-lines nil)
- )
+ (if (and leave (> leave 0)) (insert-before-markers ?\n)))
+ (setq woman-leave-blank-lines nil))
;; `fill-region-as-paragraph' in `fill.el' appears to be the principal
;; text filling function, so that is what I use here.
(skip-syntax-forward " ")
;; Successive control lines are sufficiently common to be worth a
;; special case (maybe):
- (if (>= (point) to) ; >= as a precaution!
- ()
- ;; (woman-leave-blank-lines)
+ (unless (>= (point) to)
(woman-reset-nospace)
- ;; (woman2-process-escapes to) ; 7 October 1999
(woman2-process-escapes to 'numeric)
(if woman-nofill
;; Indent without filling or adjusting ...
(progn
(woman-leave-blank-lines)
- (cond (woman-temp-indent
- (indent-to woman-temp-indent)
- (forward-line)))
+ (when woman-temp-indent
+ (indent-to woman-temp-indent)
+ (forward-line))
(indent-rigidly (point) to left-margin)
- (woman-horizontal-escapes to)) ; 7 October 1999
+ (woman-horizontal-escapes to))
;; Fill and justify ...
;; Blank lines and initial spaces cause a break.
-; (cond ((and (= (point) to) (not (looking-at ".nf"))) ; Yuk!!!
-; ;; No text after a request that caused a break, so delete
-; ;; any spurious blank line left:
-; (forward-line -1)
-; (if (looking-at "^\\s *$") (kill-line) (forward-line))))
(while (< (point) to)
(woman-leave-blank-lines)
(let ((from (point)))
(woman-horizontal-escapes to) ; 7 October 1999
;; Find the beginning of the next paragraph:
(forward-line)
-; (if (re-search-forward "\\(^\\s *$\\)\\|\\(^\\s +\\)" to 1)
-; ;; A blank line should leave a space like .sp 1 (p. 14).
-; (if (eolp)
-; (progn
-; (skip-syntax-forward " ")
-; (setq woman-leave-blank-lines 1))
-; (setq woman-leave-blank-lines nil)))
(and (re-search-forward "\\(^\\s *$\\)\\|\\(^\\s +\\)" to 1)
;; A blank line should leave a space like .sp 1 (p. 14).
(eolp)
;; If a single short line then just leave it.
;; This is necessary to preserve some table layouts.
;; PROBABLY NOT NECESSARY WITH SQUEEZE MODIFICATION !!!!!
- (if (or (> (count-lines from (point)) 1)
+ (when (or (> (count-lines from (point)) 1)
+ (save-excursion
+ (backward-char)
+ (> (current-column) fill-column)))
+ ;; NOSQUEEZE has no effect if JUSTIFY is full, so redefine
+ ;; canonically-space-region, see above.
+ (if (and woman-temp-indent (< woman-temp-indent left-margin))
+ (let ((left-margin woman-temp-indent))
+ (fill-region-as-paragraph from (point) woman-justify)
(save-excursion
- (backward-char)
- (> (current-column) fill-column)))
- ;; ?roff does not squeeze multiple spaces
- ;; (fill-region-as-paragraph from (point) woman-justify t)
- ;; NOSQUEEZE has no effect if JUSTIFY is full, so
- ;; redefine canonically-space-region, see above.
- (progn
- ;; Needs a re-write of the paragraph formatter to
- ;; avoid this nonsense to handle temporary indents!
- (if (and woman-temp-indent (< woman-temp-indent left-margin))
- (let ((left-margin woman-temp-indent))
- (fill-region-as-paragraph from (point) woman-justify)
- (save-excursion
- (goto-char from)
- (forward-line)
- (setq from (point)))))
- (fill-region-as-paragraph from (point) woman-justify))
- )
- ;; A blank line should leave a space like .sp 1 (p. 14).
- ;; Delete all but 1 trailing blank lines:
- ;;(woman-leave-blank-lines 1)
- ))
- )
- (setq woman-temp-indent nil)
- ;; Non-white-space text has been processed, so ...
- ;;(setq woman-leave-blank-lines nil)
- ))
+ (goto-char from)
+ (forward-line)
+ (setq from (point)))))
+ (fill-region-as-paragraph from (point) woman-justify)))))
+ (setq woman-temp-indent nil)))
\f
;;; Tagged, indented and hanging paragraphs:
(if (string= (match-string 1) "ta") ; for GetInt.3
(woman2-ta to)
(woman-set-interparagraph-distance)))
- (set-marker to (woman-find-next-control-line-carefully))
- ))
+ (set-marker to (woman-find-next-control-line-carefully))))
(let ((tag (point)))
(woman-reset-nospace)
;; Cannot simply delete (current-column) whitespace
;; characters because some may be tabs!
(insert-char ?\s i)))
- (goto-char to) ; necessary ???
- ))
- ))
+ (goto-char to)))))
(defun woman2-HP (to)
".HP i -- Set prevailing indent to i. Format paragraphs upto TO.
(let ((i (woman2-get-prevailing-indent)))
(woman-interparagraph-space)
(setq woman-temp-indent woman-left-margin)
- (woman2-format-paragraphs to (+ woman-left-margin i))
- ))
+ (woman2-format-paragraphs to (+ woman-left-margin i))))
(defun woman2-get-prevailing-indent (&optional leave-eol)
"Set prevailing indent to integer argument at point, and return it.
tab stop columns or pairs (COLUMN . TYPE) where TYPE is R or C."
;; Based on tab-to-tab-stop in indent.el.
;; R & C tabs probably not quite right!
- (delete-backward-char 1)
+ (delete-char -1)
(let ((tabs tab-stop-list))
(while (and tabs (>= (current-column)
(woman-get-tab-stop (car tabs))))
eol n)
(if type
(setq tab (woman-get-tab-stop tab)
- eol (save-excursion (end-of-line) (point))
+ eol (line-end-position)
n (save-excursion
(search-forward "\t" eol t))
n (- (if n (1- n) eol) (point))
(delete-char 1)
(insert woman-unpadded-space-char)
(goto-char (match-end 0))
- (delete-backward-char 1)
+ (delete-char -1)
(insert-before-markers woman-unpadded-space-char)
(subst-char-in-region
(match-beginning 0) (match-end 0)
- pad woman-unpadded-space-char t)
- ))
- ))
+ pad woman-unpadded-space-char t)))))
(woman2-format-paragraphs to))
\f
(concat "file " WoMan-current-file)
(concat "buffer " WoMan-current-buffer))
" at " (current-time-string) "\n")
- (setq WoMan-Log-header-point-max (point-max))
- )))
+ (setq WoMan-Log-header-point-max (point-max)))))
(defun WoMan-log (format &rest args)
"Log a message out of FORMAT control string and optional ARGS."
(setq format (apply 'format format args))
(WoMan-log-1 (concat "** " format)))
+;; request is not used dynamically by any callees.
(defun WoMan-warn-ignored (request ignored)
"Log a warning message about ignored directive REQUEST.
IGNORED is a string appended to the log message."
(let ((tail
(buffer-substring (point)
- (save-excursion (end-of-line) (point)))))
+ (line-end-position))))
(if (and (> (length tail) 0)
(/= (string-to-char tail) ?\ ))
(setq tail (concat " " tail)))
(cond (WoMan-Log-header-point-max
(goto-char WoMan-Log-header-point-max)
(forward-line -1)
- (recenter 0)))
- )))))
+ (recenter 0))))))))
nil) ; for woman-file-readable-p etc.
+;;; Bookmark Woman support.
+(declare-function bookmark-make-record-default
+ "bookmark" (&optional no-file no-context posn))
+(declare-function bookmark-prop-get "bookmark" (bookmark prop))
+(declare-function bookmark-default-handler "bookmark" (bmk))
+(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
+
+;; FIXME: woman.el and man.el should be better integrated so, for
+;; example, bookmarks of one can be used with the other.
+
+(defun woman-bookmark-make-record ()
+ "Make a bookmark entry for a Woman buffer."
+ `(,(Man-default-bookmark-title)
+ ,@(bookmark-make-record-default 'no-file)
+ (location . ,(concat "woman " woman-last-file-name))
+ ;; Use the same form as man's bookmarks, as much as possible.
+ (man-args . ,woman-last-file-name)
+ (handler . woman-bookmark-jump)))
+
+;;;###autoload
+(defun woman-bookmark-jump (bookmark)
+ "Default bookmark handler for Woman buffers."
+ (let* ((file (bookmark-prop-get bookmark 'man-args))
+ ;; FIXME: we need woman-find-file-noselect, since
+ ;; save-window-excursion can't protect us from the case where
+ ;; woman-find-file creates a new frame.
+ (buf (save-window-excursion
+ (woman-find-file file) (current-buffer))))
+ (bookmark-default-handler
+ `("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bookmark)))))
+
(provide 'woman)
-;; arch-tag: eea35e90-552f-4712-a94b-d9ffd3db7651
;;; woman.el ends here