comparison lisp/woman.el @ 88155:d7ddb3e565de

sync with trunk
author Henrik Enberg <henrik.enberg@telia.com>
date Mon, 16 Jan 2006 00:03:54 +0000
parents 99be3a1e2589
children
comparison
equal deleted inserted replaced
88154:8ce476d3ba36 88155:d7ddb3e565de
1 ;;; woman.el --- browse UN*X manual pages `wo (without) man' 1 ;;; woman.el --- browse UN*X manual pages `wo (without) man'
2 2
3 ;; Copyright (C) 2000, 2002 Free Software Foundation, Inc. 3 ;; Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4 4
5 ;; Author: Francis J. Wright <F.J.Wright@qmul.ac.uk> 5 ;; Author: Francis J. Wright <F.J.Wright@qmul.ac.uk>
6 ;; Maintainer: Francis J. Wright <F.J.Wright@qmul.ac.uk> 6 ;; Maintainer: FSF
7 ;; Keywords: help, unix 7 ;; Keywords: help, unix
8 ;; Adapted-By: Eli Zaretskii <eliz@is.elta.co.il> 8 ;; Adapted-By: Eli Zaretskii <eliz@gnu.org>
9 ;; Version: see `woman-version' 9 ;; Version: see `woman-version'
10 ;; URL: http://centaur.maths.qmul.ac.uk/Emacs/WoMan/ 10 ;; URL: http://centaur.maths.qmul.ac.uk/Emacs/WoMan/
11 11
12 ;; This file is part of GNU Emacs. 12 ;; This file is part of GNU Emacs.
13 13
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details. 22 ;; GNU General Public License for more details.
23 23
24 ;; You should have received a copy of the GNU General Public License 24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the 25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02111-1307, USA. 27 ;; Boston, MA 02110-1301, USA.
28 28
29 ;;; Commentary: 29 ;;; Commentary:
30 30
31 ;; WoMan implements a subset of the formatting performed by the Emacs 31 ;; WoMan implements a subset of the formatting performed by the Emacs
32 ;; `man' (or `manual-entry') command to format a UN*X manual `page' 32 ;; `man' (or `manual-entry') command to format a UN*X manual `page'
134 ;; Start menu) just execute 134 ;; Start menu) just execute
135 135
136 ;; man man_page_name 136 ;; man man_page_name
137 137
138 138
139 ;; Using the `word at point' as a topic suggestion 139 ;; Using the word at point as the default topic
140 ;; =============================================== 140 ;; ============================================
141 141
142 ;; By default, the `woman' command uses the word nearest to point in 142 ;; The `woman' command uses the word nearest to point in the current
143 ;; the current buffer as a suggestion for the topic to look up. The 143 ;; buffer as the default topic to look up if it matches the name of a
144 ;; topic must be confirmed or edited in the minibuffer. This 144 ;; manual page installed on the system. The default topic can also be
145 ;; suggestion can be turned off, or `woman' can use the suggested 145 ;; used without confirmation by setting the user-option
146 ;; topic without confirmation* if possible, by setting the user-option 146 ;; `woman-use-topic-at-point' to t; thanks to Benjamin Riefenstahl for
147 ;; `woman-topic-at-point' to nil or t respectively. (Its default 147 ;; suggesting this functionality.
148 ;; value is neither nil nor t, meaning ask for confirmation.) 148
149 149 ;; The variable `woman-use-topic-at-point' can be rebound locally,
150 ;; [* Thanks to Benjamin Riefenstahl for suggesting this 150 ;; which may be useful to provide special private key bindings, e.g.
151 ;; functionality.]
152
153 ;; The variable `woman-topic-at-point' can be rebound locally, which
154 ;; may be useful to provide special private key bindings, e.g.
155 151
156 ;; (global-set-key "\C-cw" 152 ;; (global-set-key "\C-cw"
157 ;; (lambda () 153 ;; (lambda ()
158 ;; (interactive) 154 ;; (interactive)
159 ;; (let ((woman-topic-at-point t)) 155 ;; (let ((woman-use-topic-at-point t))
160 ;; (woman))))) 156 ;; (woman)))))
161 157
162 158
163 ;; Customization, Hooks and Imenu 159 ;; Customization, Hooks and Imenu
164 ;; ============================== 160 ;; ==============================
400 ;; Nicolai Henriksen <nhe@lyngso-industri.dk> 396 ;; Nicolai Henriksen <nhe@lyngso-industri.dk>
401 ;; Thomas Herchenroeder <the@software-ag.de> 397 ;; Thomas Herchenroeder <the@software-ag.de>
402 ;; Alexander Hinds <ahinds@thegrid.net> 398 ;; Alexander Hinds <ahinds@thegrid.net>
403 ;; Stefan Hornburg <sth@hacon.de> 399 ;; Stefan Hornburg <sth@hacon.de>
404 ;; Theodore Jump <tjump@cais.com> 400 ;; Theodore Jump <tjump@cais.com>
401 ;; David Kastrup <dak@gnu.org>
405 ;; Paul Kinnucan <paulk@mathworks.com> 402 ;; Paul Kinnucan <paulk@mathworks.com>
406 ;; Jonas Linde <jonas@init.se> 403 ;; Jonas Linde <jonas@init.se>
407 ;; Andrew McRae <andrewm@optimation.co.nz> 404 ;; Andrew McRae <andrewm@optimation.co.nz>
408 ;; Howard Melman <howard@silverstream.com> 405 ;; Howard Melman <howard@silverstream.com>
409 ;; Dennis Pixton <dennis@math.binghamton.edu> 406 ;; Dennis Pixton <dennis@math.binghamton.edu>
417 ;; Karel Sprenger <ks@ic.uva.nl> 414 ;; Karel Sprenger <ks@ic.uva.nl>
418 ;; Chris Szurgot <szurgot@itribe.net> 415 ;; Chris Szurgot <szurgot@itribe.net>
419 ;; Paul A. Thompson <pat@po.cwru.edu> 416 ;; Paul A. Thompson <pat@po.cwru.edu>
420 ;; Arrigo Triulzi <arrigo@maths.qmw.ac.uk> 417 ;; Arrigo Triulzi <arrigo@maths.qmw.ac.uk>
421 ;; Geoff Voelker <voelker@cs.washington.edu> 418 ;; Geoff Voelker <voelker@cs.washington.edu>
422 ;; Eli Zaretskii <eliz@is.elta.co.il> 419 ;; Eli Zaretskii <eliz@gnu.org>
423
424 ;;; History:
425 ;; For recent change log see end of file.
426 420
427 421
428 ;;; Code: 422 ;;; Code:
429 423
430 (defvar woman-version "0.551 (beta)" "WoMan version information.") 424 (defvar woman-version "0.551 (beta)" "WoMan version information.")
431 425
432 (require 'man) 426 (require 'man)
427 (require 'button)
428 (define-button-type 'WoMan-xref-man-page
429 :supertype 'Man-abstract-xref-man-page
430 'func 'woman)
431
433 (eval-when-compile ; to avoid compiler warnings 432 (eval-when-compile ; to avoid compiler warnings
434 (require 'dired) 433 (require 'dired)
435 (require 'apropos)) 434 (require 'apropos))
436 435
437 (defun woman-mapcan (fn x) 436 (defun woman-mapcan (fn x)
438 "Return concatenated list of FN applied to successive `car' elements of X. 437 "Return concatenated list of FN applied to successive `car' elements of X.
439 FN must return a list, cons or nil. Useful for splicing into a list." 438 FN must return a list, cons or nil. Useful for splicing into a list."
440 ;; Based on the Standard Lisp function MAPCAN but with args swapped! 439 ;; Based on the Standard Lisp function MAPCAN but with args swapped!
441 (and x (nconc (funcall fn (car x)) (woman-mapcan fn (cdr x))))) 440 ;; More concise implementation than the recursive one. -- dak
441 (apply #'nconc (mapcar fn x)))
442 442
443 (defun woman-parse-colon-path (paths) 443 (defun woman-parse-colon-path (paths)
444 "Explode search path string PATHS into a list of directory names. 444 "Explode search path string PATHS into a list of directory names.
445 Allow Cygwin colon-separated search paths on Microsoft platforms. 445 Allow Cygwin colon-separated search paths on Microsoft platforms.
446 Replace null components by calling `woman-parse-man.conf'. 446 Replace null components by calling `woman-parse-man.conf'.
537 (let ((path '("/usr/lib" "/etc"))) 537 (let ((path '("/usr/lib" "/etc")))
538 (if (eq system-type 'windows-nt) 538 (if (eq system-type 'windows-nt)
539 (mapcar 'woman-Cyg-to-Win path) 539 (mapcar 'woman-Cyg-to-Win path)
540 path)) 540 path))
541 "*List of dirs to search and/or files to try for man config file. 541 "*List of dirs to search and/or files to try for man config file.
542 A trailing separator (`/' for UNIX etc.) on directories is optional 542 A trailing separator (`/' for UNIX etc.) on directories is optional,
543 and the filename used if a directory is specified is the first to 543 and the filename is used if a directory specified is the first to
544 match the regexp \"man.*\\.conf\". 544 contain the strings \"man\" and \".conf\" (in that order).
545 If MANPATH is not set but a config file is found then it is parsed 545 If MANPATH is not set but a config file is found then it is parsed
546 instead to provide a default value for `woman-manpath'." 546 instead to provide a default value for `woman-manpath'."
547 :type '(repeat string) 547 :type '(repeat string)
548 :group 'woman-interface) 548 :group 'woman-interface)
549 549
552 Used only if MANPATH is not set or contains null components. 552 Used only if MANPATH is not set or contains null components.
553 Look in `woman-man.conf-path' and return a value for `woman-manpath'. 553 Look in `woman-man.conf-path' and return a value for `woman-manpath'.
554 Concatenate data from all lines in the config file of the form 554 Concatenate data from all lines in the config file of the form
555 MANPATH /usr/man 555 MANPATH /usr/man
556 or 556 or
557 MANDATORY_MANPATH /usr/man" 557 MANDATORY_MANPATH /usr/man
558 or
559 OPTIONAL_MANPATH /usr/man"
558 ;; Functionality suggested by Charles Curley. 560 ;; Functionality suggested by Charles Curley.
559 (let ((path woman-man.conf-path) 561 (let ((path woman-man.conf-path)
560 file manpath) 562 file manpath)
561 (while (and 563 (while (and
562 path 564 path
572 (with-temp-buffer 574 (with-temp-buffer
573 (insert-file-contents file) 575 (insert-file-contents file)
574 (while (re-search-forward 576 (while (re-search-forward
575 ;; `\(?: ... \)' is a "shy group" 577 ;; `\(?: ... \)' is a "shy group"
576 "\ 578 "\
577 ^[ \t]*\\(?:MANDATORY_\\)?MANPATH[ \t]+\\(\\S-+\\)" nil t) 579 ^[ \t]*\\(?:MANDATORY_\\|OPTIONAL_\\)?MANPATH[ \t]+\\(\\S-+\\)" nil t)
578 (setq manpath (cons (match-string 1) manpath))) 580 (setq manpath (cons (match-string 1) manpath)))
579 manpath)) 581 manpath))
580 )) 582 ))
581 (setq path (cdr path))) 583 (setq path (cdr path)))
582 (nreverse manpath))) 584 (nreverse manpath)))
708 "*The title to use if WoMan adds a Contents menu to the menubar. 710 "*The title to use if WoMan adds a Contents menu to the menubar.
709 Default is \"CONTENTS\"." 711 Default is \"CONTENTS\"."
710 :type 'string 712 :type 'string
711 :group 'woman-interface) 713 :group 'woman-interface)
712 714
713 (defcustom woman-topic-at-point-default 'confirm 715 (defcustom woman-use-topic-at-point-default nil
714 ;; `woman-topic-at-point' may be let-bound when woman is loaded, in 716 ;; `woman-use-topic-at-point' may be let-bound when woman is loaded,
715 ;; which case its global value does not get defined. 717 ;; in which case its global value does not get defined.
716 ;; `woman-file-name' sets it to this value if it is unbound. 718 ;; `woman-file-name' sets it to this value if it is unbound.
717 "*Default value for `woman-topic-at-point'." 719 "*Default value for `woman-use-topic-at-point'."
718 :type '(choice (const :tag "Yes" t) 720 :type '(choice (const :tag "Yes" t)
719 (const :tag "No" nil) 721 (const :tag "No" nil))
720 (other :tag "Confirm" confirm))
721 :group 'woman-interface) 722 :group 'woman-interface)
722 723
723 (defcustom woman-topic-at-point woman-topic-at-point-default 724 (defcustom woman-use-topic-at-point woman-use-topic-at-point-default
724 "*Controls use by `woman' of `word at point' as a topic suggestion. 725 "*Control use of the word at point as the default topic.
725 If non-nil then the `woman' command uses the word at point as an 726 If non-nil the `woman' command uses the word at point automatically,
726 initial topic suggestion when it reads a topic from the minibuffer; if 727 without interactive confirmation, if it exists as a topic."
727 t then the `woman' command uses the word at point WITHOUT
728 INTERACTIVE CONFIRMATION if it exists as a topic. The default value
729 is `confirm', meaning suggest a topic and ask for confirmation."
730 :type '(choice (const :tag "Yes" t) 728 :type '(choice (const :tag "Yes" t)
731 (const :tag "No" nil) 729 (const :tag "No" nil))
732 (other :tag "Confirm" confirm))
733 :group 'woman-interface) 730 :group 'woman-interface)
734 731
735 (defvar woman-file-regexp nil 732 (defvar woman-file-regexp nil
736 "Regexp used to select (possibly compressed) man source files, e.g. 733 "Regexp used to select (possibly compressed) man source files, e.g.
737 \"\\.\\([0-9lmnt]\\w*\\)\\(\\.\\(g?z\\|bz2\\)\\)?\\'\". 734 \"\\.\\([0-9lmnt]\\w*\\)\\(\\.\\(g?z\\|bz2\\)\\)?\\'\".
805 :type 'integer 802 :type 'integer
806 :group 'woman-formatting) 803 :group 'woman-formatting)
807 804
808 (defcustom woman-fill-frame nil 805 (defcustom woman-fill-frame nil
809 ;; Based loosely on a suggestion by Theodore Jump: 806 ;; Based loosely on a suggestion by Theodore Jump:
810 "*If non-nil then most of the frame width is used." 807 "*If non-nil then most of the window width is used."
811 :type 'boolean 808 :type 'boolean
812 :group 'woman-formatting) 809 :group 'woman-formatting)
813 810
814 (defcustom woman-default-indent 5 811 (defcustom woman-default-indent 5
815 "*Default prevailing indent set by -man macros -- default is 5. 812 "*Default prevailing indent set by -man macros -- default is 5.
817 :type 'integer 814 :type 'integer
818 :group 'woman-formatting) 815 :group 'woman-formatting)
819 816
820 (defcustom woman-bold-headings t 817 (defcustom woman-bold-headings t
821 "*If non-nil then embolden section and subsection headings. Default is t. 818 "*If non-nil then embolden section and subsection headings. Default is t.
822 Heading emboldening is NOT standard `man' behaviour." 819 Heading emboldening is NOT standard `man' behavior."
823 :type 'boolean 820 :type 'boolean
824 :group 'woman-formatting) 821 :group 'woman-formatting)
825 822
826 (defcustom woman-ignore t 823 (defcustom woman-ignore t
827 "*If non-nil then unrecognised requests etc. are ignored. Default is t. 824 "*If non-nil then unrecognized requests etc. are ignored. Default is t.
828 This gives the standard ?roff behaviour. If nil then they are left in 825 This gives the standard ?roff behavior. If nil then they are left in
829 the buffer, which may aid debugging." 826 the buffer, which may aid debugging."
830 :type 'boolean 827 :type 'boolean
831 :group 'woman-formatting) 828 :group 'woman-formatting)
832 829
833 (defcustom woman-preserve-ascii nil 830 (defcustom woman-preserve-ascii t
834 "*If non-nil then preserve ASCII characters in the WoMan buffer. 831 "*If non-nil, preserve ASCII characters in the WoMan buffer.
835 Otherwise, non-ASCII characters (that display as ASCII) may remain. 832 Otherwise, to save time, some backslashes and spaces may be
836 This is irrelevant unless the buffer is to be saved to a file." 833 represented differently (as the values of the variables
834 `woman-escaped-escape-char' and `woman-unpadded-space-char'
835 respectively) so that the buffer content is strictly wrong even though
836 it should display correctly. This should be irrelevant unless the
837 buffer text is searched, copied or saved to a file."
838 ;; This option should probably be removed!
837 :type 'boolean 839 :type 'boolean
838 :group 'woman-formatting) 840 :group 'woman-formatting)
839 841
840 (defcustom woman-emulation 'nroff 842 (defcustom woman-emulation 'nroff
841 "*WoMan emulation, currently either nroff or troff. Default is nroff. 843 "*WoMan emulation, currently either nroff or troff. Default is nroff.
864 :group 'woman-faces) 866 :group 'woman-faces)
865 867
866 ;; This is overkill! Troff uses just italic; Nroff uses just underline. 868 ;; This is overkill! Troff uses just italic; Nroff uses just underline.
867 ;; You should probably select either italic or underline as you prefer, but 869 ;; You should probably select either italic or underline as you prefer, but
868 ;; not both, although italic and underline work together perfectly well! 870 ;; not both, although italic and underline work together perfectly well!
869 (defface woman-italic-face 871 (defface woman-italic
870 `((((background light)) (:slant italic :underline t :foreground "red")) 872 `((((min-colors 88) (background light))
873 (:slant italic :underline t :foreground "red1"))
874 (((background light)) (:slant italic :underline t :foreground "red"))
871 (((background dark)) (:slant italic :underline t))) 875 (((background dark)) (:slant italic :underline t)))
872 "Face for italic font in man pages." 876 "Face for italic font in man pages."
873 :group 'woman-faces) 877 :group 'woman-faces)
874 878 ;; backward-compatibility alias
875 (defface woman-bold-face 879 (put 'woman-italic-face 'face-alias 'woman-italic)
876 '((((background light)) (:weight bold :foreground "blue")) 880
881 (defface woman-bold
882 '((((min-colors 88) (background light)) (:weight bold :foreground "blue1"))
883 (((background light)) (:weight bold :foreground "blue"))
877 (((background dark)) (:weight bold :foreground "green2"))) 884 (((background dark)) (:weight bold :foreground "green2")))
878 "Face for bold font in man pages." 885 "Face for bold font in man pages."
879 :group 'woman-faces) 886 :group 'woman-faces)
887 ;; backward-compatibility alias
888 (put 'woman-bold-face 'face-alias 'woman-bold)
880 889
881 ;; Brown is a good compromise: it is distinguishable from the default 890 ;; Brown is a good compromise: it is distinguishable from the default
882 ;; but not enough so to make font errors look terrible. (Files that use 891 ;; but not enough so to make font errors look terrible. (Files that use
883 ;; non-standard fonts seem to do so badly or in idiosyncratic ways!) 892 ;; non-standard fonts seem to do so badly or in idiosyncratic ways!)
884 (defface woman-unknown-face 893 (defface woman-unknown
885 '((((background light)) (:foreground "brown")) 894 '((((background light)) (:foreground "brown"))
895 (((min-colors 88) (background dark)) (:foreground "cyan1"))
886 (((background dark)) (:foreground "cyan"))) 896 (((background dark)) (:foreground "cyan")))
887 "Face for all unknown fonts in man pages." 897 "Face for all unknown fonts in man pages."
888 :group 'woman-faces) 898 :group 'woman-faces)
889 899 ;; backward-compatibility alias
890 (defface woman-addition-face 900 (put 'woman-unknown-face 'face-alias 'woman-unknown)
901
902 (defface woman-addition
891 '((t (:foreground "orange"))) 903 '((t (:foreground "orange")))
892 "Face for all WoMan additions to man pages." 904 "Face for all WoMan additions to man pages."
893 :group 'woman-faces) 905 :group 'woman-faces)
906 ;; backward-compatibility alias
907 (put 'woman-addition-face 'face-alias 'woman-addition)
894 908
895 (defun woman-default-faces () 909 (defun woman-default-faces ()
896 "Set foreground colours of italic and bold faces to their default values." 910 "Set foreground colors of italic and bold faces to their default values."
897 (interactive) 911 (interactive)
898 (face-spec-set 'woman-italic-face 912 (face-spec-set 'woman-italic (face-user-default-spec 'woman-italic))
899 (face-user-default-spec 'woman-italic-face)) 913 (face-spec-set 'woman-bold (face-user-default-spec 'woman-bold)))
900 (face-spec-set 'woman-bold-face (face-user-default-spec 'woman-bold-face)))
901 914
902 (defun woman-monochrome-faces () 915 (defun woman-monochrome-faces ()
903 "Set foreground colours of italic and bold faces to that of the default face. 916 "Set foreground colors of italic and bold faces to that of the default face.
904 This is usually either black or white." 917 This is usually either black or white."
905 (interactive) 918 (interactive)
906 (set-face-foreground 'woman-italic-face 'unspecified) 919 (set-face-foreground 'woman-italic 'unspecified)
907 (set-face-foreground 'woman-bold-face 'unspecified)) 920 (set-face-foreground 'woman-bold 'unspecified))
908 921
909 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 922 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
910 ;; Experimental font support, initially only for MS-Windows. 923 ;; Experimental font support, initially only for MS-Windows.
911 (defconst woman-font-support 924 (defconst woman-font-support
912 (eq window-system 'w32) ; Support X later! 925 (eq window-system 'w32) ; Support X later!
923 (setq symbol-fonts (cons (car fonts) symbol-fonts))) 936 (setq symbol-fonts (cons (car fonts) symbol-fonts)))
924 (setq fonts (cdr fonts))) 937 (setq fonts (cdr fonts)))
925 symbol-fonts)) 938 symbol-fonts))
926 939
927 (when woman-font-support 940 (when woman-font-support
928 (make-face 'woman-symbol-face) 941 (make-face 'woman-symbol)
929 942
930 ;; Set the symbol font only if `woman-use-symbol-font' is true, to 943 ;; Set the symbol font only if `woman-use-symbol-font' is true, to
931 ;; avoid unnecessarily upsetting the line spacing in NTEmacs 20.5! 944 ;; avoid unnecessarily upsetting the line spacing in NTEmacs 20.5!
932 945
933 (defcustom woman-use-extended-font t 946 (defcustom woman-use-extended-font t
934 "*If non-nil then may use non-ASCII characters from the default font." 947 "*If non-nil then may use non-ASCII characters from the default font."
935 :type 'boolean 948 :type 'boolean
936 :group 'woman-faces) 949 :group 'woman-faces)
937 950
938 (defcustom woman-use-symbol-font nil 951 (defcustom woman-use-symbol-font nil
939 "*If non-nil then may use the symbol font. It is off by default, 952 "*If non-nil then may use the symbol font.
940 mainly because it may change the line spacing (in NTEmacs 20.5)." 953 It is off by default, mainly because it may change the line spacing
954 \(in NTEmacs 20.5)."
941 :type 'boolean 955 :type 'boolean
942 :group 'woman-faces) 956 :group 'woman-faces)
943 957
944 (defconst woman-symbol-font-list 958 (defconst woman-symbol-font-list
945 (or (woman-select-symbol-fonts (x-list-fonts "*" 'default)) 959 (or (woman-select-symbol-fonts (x-list-fonts "*" 'default))
1013 1027
1014 (defsubst woman-reset-nospace () 1028 (defsubst woman-reset-nospace ()
1015 "Set `woman-nospace' to nil." 1029 "Set `woman-nospace' to nil."
1016 (setq woman-nospace nil)) 1030 (setq woman-nospace nil))
1017 1031
1018 (defconst woman-mode-line-format
1019 ;; This is essentially the Man-mode format with page numbers removed
1020 ;; and line numbers added. (Online documents do not have pages, but
1021 ;; they do have lines!)
1022 '("-" mode-line-mule-info mode-line-modified
1023 mode-line-frame-identification mode-line-buffer-identification
1024 " " global-mode-string
1025 " %[(WoMan" mode-line-process minor-mode-alist ")%]--"
1026 (line-number-mode "L%l--")
1027 (-3 . "%p") "-%-")
1028 "Mode line format for WoMan buffer.")
1029
1030 (defconst woman-request-regexp "^[.'][ \t]*\\(\\S +\\) *" 1032 (defconst woman-request-regexp "^[.'][ \t]*\\(\\S +\\) *"
1031 ;; Was "^\\.[ \t]*\\([a-z0-9]+\\) *" but cvs.1 uses a macro named 1033 ;; Was "^\\.[ \t]*\\([a-z0-9]+\\) *" but cvs.1 uses a macro named
1032 ;; "`" and CGI.man uses a macro named "''"! 1034 ;; "`" and CGI.man uses a macro named "''"!
1033 ;; CGI.man uses ' as control character in places -- it *should* 1035 ;; CGI.man uses ' as control character in places -- it *should*
1034 ;; suppress breaks! 1036 ;; suppress breaks!
1055 1057
1056 (defvar woman-if-conditions-true '(?n ?e ?o) 1058 (defvar woman-if-conditions-true '(?n ?e ?o)
1057 "List of one-character built-in condition names that are true. 1059 "List of one-character built-in condition names that are true.
1058 Should include ?e, ?o (page even/odd) and either ?n (nroff) or ?t (troff). 1060 Should include ?e, ?o (page even/odd) and either ?n (nroff) or ?t (troff).
1059 Default is '(?n ?e ?o). Set via `woman-emulation'.") 1061 Default is '(?n ?e ?o). Set via `woman-emulation'.")
1060
1061
1062 ;;; Button types:
1063
1064 (define-button-type 'woman-xref
1065 'action (lambda (button) (woman (button-label button)))
1066 'help-echo "RET, mouse-2: display this man page")
1067 1062
1068 1063
1069 ;;; Specialized utility functions: 1064 ;;; Specialized utility functions:
1070 1065
1071 ;;; Fast deletion without saving on the kill ring (cf. simple.el): 1066 ;;; Fast deletion without saving on the kill ring (cf. simple.el):
1128 1123
1129 Used non-interactively, arguments are optional: if given then TOPIC 1124 Used non-interactively, arguments are optional: if given then TOPIC
1130 should be a topic string and non-nil RE-CACHE forces re-caching." 1125 should be a topic string and non-nil RE-CACHE forces re-caching."
1131 (interactive (list nil current-prefix-arg)) 1126 (interactive (list nil current-prefix-arg))
1132 ;; The following test is for non-interactive calls via gnudoit etc. 1127 ;; The following test is for non-interactive calls via gnudoit etc.
1133 (if (or (interactive-p) (not (stringp topic)) (string-match "\\S " topic)) 1128 (if (or (not (stringp topic)) (string-match "\\S " topic))
1134 (let ((file-name (woman-file-name topic re-cache))) 1129 (let ((file-name (woman-file-name topic re-cache)))
1135 (if file-name 1130 (if file-name
1136 (woman-find-file file-name) 1131 (woman-find-file file-name)
1137 (message 1132 (message
1138 "WoMan Error: No matching manual files found in search path") 1133 "WoMan Error: No matching manual files found in search path")
1197 (defvar woman-topic-history nil "Topic read history.") 1192 (defvar woman-topic-history nil "Topic read history.")
1198 (defvar woman-file-history nil "File-name read history.") 1193 (defvar woman-file-history nil "File-name read history.")
1199 1194
1200 (defun woman-file-name (topic &optional re-cache) 1195 (defun woman-file-name (topic &optional re-cache)
1201 "Get the name of the UN*X man-page file describing a chosen TOPIC. 1196 "Get the name of the UN*X man-page file describing a chosen TOPIC.
1202 When `woman' is called interactively, the word at point may be used as 1197 When `woman' is called interactively, the word at point may be
1203 the topic or initial topic suggestion, subject to the value of the 1198 automatically used as the topic, if the value of the user option
1204 user option `woman-topic-at-point'. Return nil if no file can be found. 1199 `woman-use-topic-at-point' is non-nil. Return nil if no file can
1205 Optional argument RE-CACHE, if non-nil, forces the cache to be re-read." 1200 be found. Optional argument RE-CACHE, if non-nil, forces the
1201 cache to be re-read."
1206 ;; Handle the caching of the directory and topic lists: 1202 ;; Handle the caching of the directory and topic lists:
1207 (if (and (not re-cache) 1203 (if (and (not re-cache)
1208 (or 1204 (or
1209 (and woman-expanded-directory-path woman-topic-all-completions) 1205 (and woman-expanded-directory-path woman-topic-all-completions)
1210 (woman-read-directory-cache))) 1206 (woman-read-directory-cache)))
1218 (woman-write-directory-cache)) 1214 (woman-write-directory-cache))
1219 ;; There is a problem in that I want to offer case-insensitive 1215 ;; There is a problem in that I want to offer case-insensitive
1220 ;; completions, but to return only a case-sensitive match. This 1216 ;; completions, but to return only a case-sensitive match. This
1221 ;; does not seem to work properly by default, so I re-do the 1217 ;; does not seem to work properly by default, so I re-do the
1222 ;; completion if necessary. 1218 ;; completion if necessary.
1223 (let (files) 1219 (let (files
1220 (default (current-word)))
1224 (or (stringp topic) 1221 (or (stringp topic)
1225 (and (eq t 1222 (and (if (boundp 'woman-use-topic-at-point)
1226 (if (boundp 'woman-topic-at-point) 1223 woman-use-topic-at-point
1227 woman-topic-at-point 1224 ;; Was let-bound when file loaded, so ...
1228 ;; Was let-bound when file loaded, so ... 1225 (setq woman-use-topic-at-point woman-use-topic-at-point-default))
1229 (setq woman-topic-at-point woman-topic-at-point-default))) 1226 (setq topic (or (current-word t) "")) ; only within or adjacent to word
1230 (setq topic 1227 (test-completion topic woman-topic-all-completions))
1231 (current-word t)) ; only within or adjacent to word
1232 (assoc topic woman-topic-all-completions))
1233 (setq topic 1228 (setq topic
1234 (completing-read 1229 (let* ((word-at-point (current-word))
1235 "Manual entry: " 1230 (default
1236 woman-topic-all-completions nil 1 1231 (when (and word-at-point
1237 ;; Initial input suggestion (was nil), with 1232 (test-completion
1238 ;; cursor at left ready to kill suggestion!: 1233 word-at-point woman-topic-all-completions))
1239 (and woman-topic-at-point 1234 word-at-point)))
1240 (cons (current-word) 0)) ; nearest word 1235 (completing-read
1241 'woman-topic-history))) 1236 (if default
1237 (format "Manual entry (default %s): " default)
1238 "Manual entry: ")
1239 woman-topic-all-completions nil 1
1240 nil
1241 'woman-topic-history
1242 default))))
1242 ;; Note that completing-read always returns a string. 1243 ;; Note that completing-read always returns a string.
1243 (if (= (length topic) 0) 1244 (if (= (length topic) 0)
1244 nil ; no topic, so no file! 1245 nil ; no topic, so no file!
1245 (cond 1246 (cond
1246 ((setq files (woman-file-name-all-completions topic))) 1247 ((setq files (woman-file-name-all-completions topic)))
1256 (t 1257 (t
1257 ;; Multiple files for topic, so must select 1. 1258 ;; Multiple files for topic, so must select 1.
1258 ;; Unread the command event (TAB = ?\t = 9) that runs the command 1259 ;; Unread the command event (TAB = ?\t = 9) that runs the command
1259 ;; `minibuffer-complete' in order to automatically complete the 1260 ;; `minibuffer-complete' in order to automatically complete the
1260 ;; minibuffer contents as far as possible. 1261 ;; minibuffer contents as far as possible.
1261 (setq unread-command-events '(9)) ; and delete any type-ahead! 1262 (setq unread-command-events '(9)) ; and delete any type-ahead!
1262 (completing-read "Manual file: " files nil 1 1263 (completing-read "Manual file: " files nil 1
1263 (try-completion "" files) 'woman-file-history))) 1264 (try-completion "" files) 'woman-file-history))))))
1264 )))
1265 1265
1266 (defun woman-select (predicate list) 1266 (defun woman-select (predicate list)
1267 "Select unique elements for which PREDICATE is true in LIST. 1267 "Select unique elements for which PREDICATE is true in LIST.
1268 \(Note that this function changes the value of LIST.)" 1268 \(Note that this function changes the value of LIST.)"
1269 ;; Intended to be fast by avoiding recursion and list copying. 1269 ;; Intended to be fast by avoiding recursion and list copying.
1365 ;; will be a list of the first `woman-cache-level' elements of the 1365 ;; will be a list of the first `woman-cache-level' elements of the
1366 ;; following list: (topic path-index filename). This alist `files' 1366 ;; following list: (topic path-index filename). This alist `files'
1367 ;; is re-processed by `woman-topic-all-completions-merge'. 1367 ;; is re-processed by `woman-topic-all-completions-merge'.
1368 (let (dir files (path-index 0)) ; indexing starts at zero 1368 (let (dir files (path-index 0)) ; indexing starts at zero
1369 (while path 1369 (while path
1370 (setq dir (car path) 1370 (setq dir (pop path))
1371 path (cdr path))
1372 (if (woman-not-member dir path) ; use each directory only once! 1371 (if (woman-not-member dir path) ; use each directory only once!
1373 (setq files 1372 (push (woman-topic-all-completions-1 dir path-index)
1374 (nconc files 1373 files))
1375 (woman-topic-all-completions-1 dir path-index))))
1376 (setq path-index (1+ path-index))) 1374 (setq path-index (1+ path-index)))
1377 ;; Uniquefy topics: 1375 ;; Uniquefy topics:
1378 (woman-topic-all-completions-merge files))) 1376 ;; Concate all lists with a single nconc call to
1377 ;; avoid retraversing the first lists repeatedly -- dak
1378 (woman-topic-all-completions-merge
1379 (apply #'nconc files))))
1379 1380
1380 (defun woman-topic-all-completions-1 (dir path-index) 1381 (defun woman-topic-all-completions-1 (dir path-index)
1381 "Return an alist of the man topics in directory DIR with index PATH-INDEX. 1382 "Return an alist of the man topics in directory DIR with index PATH-INDEX.
1382 A topic is a filename sans type-related extensions. 1383 A topic is a filename sans type-related extensions.
1383 Support 3 levels of caching: each element of the alist will be a list 1384 Support 3 levels of caching: each element of the alist will be a list
1386 ;; This function used to check that each file in the directory was 1387 ;; This function used to check that each file in the directory was
1387 ;; not itself a directory, but this is very slow and should be 1388 ;; not itself a directory, but this is very slow and should be
1388 ;; unnecessary. So let us assume that `woman-file-regexp' will 1389 ;; unnecessary. So let us assume that `woman-file-regexp' will
1389 ;; filter out any directories, which probably should not be there 1390 ;; filter out any directories, which probably should not be there
1390 ;; anyway, i.e. it is a user error! 1391 ;; anyway, i.e. it is a user error!
1391 (mapcar 1392 ;;
1392 (lambda (file) 1393 ;; Don't sort files: we do that when merging, anyway. -- dak
1393 (cons 1394 (let (newlst (lst (directory-files dir nil woman-file-regexp t))
1394 (file-name-sans-extension 1395 ;; Make an explicit regexp for stripping extension and
1395 (if (string-match woman-file-compression-regexp file) 1396 ;; compression extension: file-name-sans-extension is a
1396 (file-name-sans-extension file) 1397 ;; far too costly function. -- dak
1397 file)) 1398 (ext (format "\\(\\.[^.\\/]*\\)?\\(%s\\)?\\'"
1398 (if (> woman-cache-level 1) 1399 woman-file-compression-regexp)))
1399 (cons 1400 ;; Use a loop instead of mapcar in order to avoid the speed
1400 path-index 1401 ;; penalty of binding function arguments. -- dak
1401 (if (> woman-cache-level 2) 1402 (dolist (file lst newlst)
1402 (cons file nil)))))) 1403 (push
1403 (directory-files dir nil woman-file-regexp))) 1404 (cons
1405 (if (string-match ext file)
1406 (substring file 0 (match-beginning 0))
1407 file)
1408 (and (> woman-cache-level 1)
1409 (cons
1410 path-index
1411 (and (> woman-cache-level 2)
1412 (list file)))))
1413 newlst))))
1404 1414
1405 (defun woman-topic-all-completions-merge (alist) 1415 (defun woman-topic-all-completions-merge (alist)
1406 "Merge the alist ALIST so that the keys are unique. 1416 "Merge the alist ALIST so that the keys are unique.
1407 Also make each path-info component into a list. 1417 Also make each path-info component into a list.
1408 \(Note that this function changes the value of ALIST.)" 1418 \(Note that this function changes the value of ALIST.)"
1409 ;; Intended to be fast by avoiding recursion and list copying. 1419 ;; Replaces unreadably "optimized" O(n^2) implementation.
1410 (if (> woman-cache-level 1) 1420 ;; Instead we use sorting to merge stuff efficiently. -- dak
1411 (let ((newalist alist)) 1421 (let (elt newalist)
1412 (while newalist 1422 ;; Sort list into reverse order
1413 (let ((tail newalist) (topic (car (car newalist)))) 1423 (setq alist (sort alist (lambda(x y) (string< (car y) (car x)))))
1414 ;; Make the path-info into a list: 1424 ;; merge duplicate keys.
1415 (setcdr (car newalist) (list (cdr (car newalist)))) 1425 (if (> woman-cache-level 1)
1416 (while tail 1426 (while alist
1417 (while (and tail (not (string= topic (car (car (cdr tail)))))) 1427 (setq elt (pop alist))
1418 (setq tail (cdr tail))) 1428 (if (equal (car elt) (caar newalist))
1419 (if tail ; merge path-info into (car newalist) 1429 (unless (member (cdr elt) (cdar newalist))
1420 (let ((path-info (cdr (car (cdr tail))))) 1430 (setcdr (car newalist) (cons (cdr elt)
1421 (if (member path-info (cdr (car newalist))) 1431 (cdar newalist))))
1422 () 1432 (setcdr elt (list (cdr elt)))
1423 ;; Make the path-info into a list: 1433 (push elt newalist)))
1424 (nconc (car newalist) (list path-info)))
1425 (setcdr tail (cdr (cdr tail))))
1426 ))
1427 (setq newalist (cdr newalist))))
1428 alist)
1429 ;; woman-cache-level = 1 => elements are single-element lists ... 1434 ;; woman-cache-level = 1 => elements are single-element lists ...
1430 (while (and alist (member (car alist) (cdr alist))) 1435 (while alist
1431 (setq alist (cdr alist))) 1436 (setq elt (pop alist))
1432 (if alist 1437 (unless (equal (car elt) (caar newalist))
1433 (let ((newalist alist) cdr_alist) 1438 (push elt newalist))))
1434 (while (setq cdr_alist (cdr alist)) 1439 newalist))
1435 (if (not (member (car cdr_alist) (cdr cdr_alist)))
1436 (setq alist cdr_alist)
1437 (setcdr alist (cdr cdr_alist)))
1438 )
1439 newalist))))
1440 1440
1441 (defun woman-file-name-all-completions (topic) 1441 (defun woman-file-name-all-completions (topic)
1442 "Return an alist of the files in all man directories that match TOPIC." 1442 "Return an alist of the files in all man directories that match TOPIC."
1443 ;; Support 3 levels of caching: each element of 1443 ;; Support 3 levels of caching: each element of
1444 ;; woman-topic-all-completions is a list of one of the forms: 1444 ;; woman-topic-all-completions is a list of one of the forms:
1487 "Bind the argument KEY to the command `woman-dired-find-file'." 1487 "Bind the argument KEY to the command `woman-dired-find-file'."
1488 (define-key dired-mode-map key 'woman-dired-find-file)) 1488 (define-key dired-mode-map key 'woman-dired-find-file))
1489 1489
1490 (defsubst woman-dired-define-key-maybe (key) 1490 (defsubst woman-dired-define-key-maybe (key)
1491 "If KEY is undefined in Dired, bind it to command `woman-dired-find-file'." 1491 "If KEY is undefined in Dired, bind it to command `woman-dired-find-file'."
1492 (if (eq (lookup-key dired-mode-map key) 'undefined) 1492 (if (or (eq (lookup-key dired-mode-map key) 'undefined)
1493 (null (lookup-key dired-mode-map key)))
1493 (woman-dired-define-key key))) 1494 (woman-dired-define-key key)))
1494 1495
1495 (defun woman-dired-define-keys () 1496 (defun woman-dired-define-keys ()
1496 "Define dired keys to run WoMan according to `woman-dired-keys'." 1497 "Define dired keys to run WoMan according to `woman-dired-keys'."
1497 (if woman-dired-keys 1498 (if woman-dired-keys
1664 ;; Multibyte characters exist. 1665 ;; Multibyte characters exist.
1665 (progn 1666 (progn
1666 (goto-char (point-min)) 1667 (goto-char (point-min))
1667 (while (search-forward "__\b\b" nil t) 1668 (while (search-forward "__\b\b" nil t)
1668 (backward-delete-char 4) 1669 (backward-delete-char 4)
1669 (woman-set-face (point) (1+ (point)) 'woman-italic-face)) 1670 (woman-set-face (point) (1+ (point)) 'woman-italic))
1670 (goto-char (point-min)) 1671 (goto-char (point-min))
1671 (while (search-forward "\b\b__" nil t) 1672 (while (search-forward "\b\b__" nil t)
1672 (backward-delete-char 4) 1673 (backward-delete-char 4)
1673 (woman-set-face (1- (point)) (point) 'woman-italic-face)))) 1674 (woman-set-face (1- (point)) (point) 'woman-italic))))
1674 1675
1675 ;; Interpret overprinting to indicate bold face: 1676 ;; Interpret overprinting to indicate bold face:
1676 (goto-char (point-min)) 1677 (goto-char (point-min))
1677 (while (re-search-forward "\\(.\\)\\(\\(+\\1\\)+\\)" nil t) 1678 (while (re-search-forward "\\(.\\)\\(\\(+\\1\\)+\\)" nil t)
1678 (woman-delete-match 2) 1679 (woman-delete-match 2)
1679 (woman-set-face (1- (point)) (point) 'woman-bold-face)) 1680 (woman-set-face (1- (point)) (point) 'woman-bold))
1680 1681
1681 ;; Interpret underlining to indicate italic face: 1682 ;; Interpret underlining to indicate italic face:
1682 ;; (Must be AFTER emboldening to interpret bold _ correctly!) 1683 ;; (Must be AFTER emboldening to interpret bold _ correctly!)
1683 (goto-char (point-min)) 1684 (goto-char (point-min))
1684 (while (search-forward "_" nil t) 1685 (while (search-forward "_" nil t)
1685 (delete-char -2) 1686 (delete-char -2)
1686 (woman-set-face (point) (1+ (point)) 'woman-italic-face)) 1687 (woman-set-face (point) (1+ (point)) 'woman-italic))
1687 1688
1688 ;; Leave any other uninterpreted ^H's in the buffer for now! (They 1689 ;; Leave any other uninterpreted ^H's in the buffer for now! (They
1689 ;; might indicate composite special characters, which could be 1690 ;; might indicate composite special characters, which could be
1690 ;; interpreted if I knew what to expect.) 1691 ;; interpreted if I knew what to expect.)
1691 1692
1694 (cond 1695 (cond
1695 (woman-bold-headings 1696 (woman-bold-headings
1696 (goto-char (point-min)) 1697 (goto-char (point-min))
1697 (forward-line) 1698 (forward-line)
1698 (while (re-search-forward "^\\( \\)?\\([A-Z].*\\)" nil t) 1699 (while (re-search-forward "^\\( \\)?\\([A-Z].*\\)" nil t)
1699 (woman-set-face (match-beginning 2) (match-end 2) 'woman-bold-face)))) 1700 (woman-set-face (match-beginning 2) (match-end 2) 'woman-bold))))
1700 ) 1701 )
1701 1702
1702 (defun woman-insert-file-contents (filename compressed) 1703 (defun woman-insert-file-contents (filename compressed)
1703 "Insert file FILENAME into the current buffer. 1704 "Insert file FILENAME into the current buffer.
1704 If COMPRESSED is t, or is non-nil and the filename implies compression, 1705 If COMPRESSED is t, or is non-nil and the filename implies compression,
1729 1730
1730 ;;; Major mode (Man) interface: 1731 ;;; Major mode (Man) interface:
1731 1732
1732 (defvar woman-mode-map nil "Keymap for woman mode.") 1733 (defvar woman-mode-map nil "Keymap for woman mode.")
1733 1734
1734 (if woman-mode-map 1735 (unless woman-mode-map
1735 () 1736 (setq woman-mode-map (make-sparse-keymap))
1736 ;; Set up the keymap, mostly inherited from Man-mode-map. Normally
1737 ;; button-buffer-map is used as a parent keymap, but we can't have two
1738 ;; parents, so we just copy it.
1739 (setq woman-mode-map (copy-keymap button-buffer-map))
1740 (set-keymap-parent woman-mode-map Man-mode-map) 1737 (set-keymap-parent woman-mode-map Man-mode-map)
1741 ;; Above two lines were 1738
1742 ;; (setq woman-mode-map (cons 'keymap Man-mode-map))
1743 (define-key woman-mode-map "R" 'woman-reformat-last-file) 1739 (define-key woman-mode-map "R" 'woman-reformat-last-file)
1744 (define-key woman-mode-map "w" 'woman) 1740 (define-key woman-mode-map "w" 'woman)
1745 (define-key woman-mode-map "\en" 'WoMan-next-manpage) 1741 (define-key woman-mode-map "\en" 'WoMan-next-manpage)
1746 (define-key woman-mode-map "\ep" 'WoMan-previous-manpage) 1742 (define-key woman-mode-map "\ep" 'WoMan-previous-manpage)
1747 (define-key woman-mode-map [M-mouse-2] 'woman-follow-word)) 1743 (define-key woman-mode-map [M-mouse-2] 'woman-follow-word)
1744
1745 ;; We don't need to call `man' when we are in `woman-mode'.
1746 (define-key woman-mode-map [remap man] 'woman))
1748 1747
1749 (defun woman-follow-word (event) 1748 (defun woman-follow-word (event)
1750 "Run WoMan with word under mouse as topic. 1749 "Run WoMan with word under mouse as topic.
1751 Argument EVENT is the invoking mouse event." 1750 Argument EVENT is the invoking mouse event."
1752 (interactive "e") ; mouse event 1751 (interactive "e") ; mouse event
1753 (goto-char (posn-point (event-start event))) 1752 (goto-char (posn-point (event-start event)))
1754 (woman (current-word t))) 1753 (woman (or (current-word t) "")))
1755 1754
1756 ;; WoMan menu bar and pop-up menu: 1755 ;; WoMan menu bar and pop-up menu:
1757 (easy-menu-define 1756 (easy-menu-define
1758 woman-menu ; (SYMBOL MAPS DOC MENU) 1757 woman-menu ; (SYMBOL MAPS DOC MENU)
1759 ;; That comment was moved after the symbol `woman-menu' to make 1758 ;; That comment was moved after the symbol `woman-menu' to make
1825 "Reset `woman-emulation' to VALUE and reformat, for menu use." 1824 "Reset `woman-emulation' to VALUE and reformat, for menu use."
1826 (interactive) 1825 (interactive)
1827 (setq woman-emulation value) 1826 (setq woman-emulation value)
1828 (woman-reformat-last-file)) 1827 (woman-reformat-last-file))
1829 1828
1829 (put 'woman-mode 'mode-class 'special)
1830
1830 (defun woman-mode () 1831 (defun woman-mode ()
1831 "Turn on (most of) Man mode to browse a buffer formatted by WoMan. 1832 "Turn on (most of) Man mode to browse a buffer formatted by WoMan.
1832 WoMan is an ELisp emulation of much of the functionality of the Emacs 1833 WoMan is an ELisp emulation of much of the functionality of the Emacs
1833 `man' command running the standard UN*X man and ?roff programs. 1834 `man' command running the standard UN*X man and ?roff programs.
1834 WoMan author: F.J.Wright@Maths.QMW.ac.uk 1835 WoMan author: F.J.Wright@Maths.QMW.ac.uk
1842 (fset 'Man-build-page-list 'ignore) 1843 (fset 'Man-build-page-list 'ignore)
1843 (fset 'Man-strip-page-headers 'ignore) 1844 (fset 'Man-strip-page-headers 'ignore)
1844 (fset 'Man-unindent 'ignore) 1845 (fset 'Man-unindent 'ignore)
1845 (fset 'Man-goto-page 'ignore) 1846 (fset 'Man-goto-page 'ignore)
1846 (unwind-protect 1847 (unwind-protect
1847 (progn 1848 (delay-mode-hooks (Man-mode))
1848 (set (make-local-variable 'Man-mode-map) woman-mode-map)
1849 ;; Install Man mode:
1850 (Man-mode)
1851 ;; Reset inappropriate definitions:
1852 (setq mode-line-format woman-mode-line-format)
1853 (put 'Man-mode 'mode-class 'special))
1854 ;; Restore the status quo: 1849 ;; Restore the status quo:
1855 (fset 'Man-build-page-list Man-build-page-list) 1850 (fset 'Man-build-page-list Man-build-page-list)
1856 (fset 'Man-strip-page-headers Man-strip-page-headers) 1851 (fset 'Man-strip-page-headers Man-strip-page-headers)
1857 (fset 'Man-unindent Man-unindent) 1852 (fset 'Man-unindent Man-unindent)
1858 (fset 'Man-goto-page Man-goto-page) 1853 (fset 'Man-goto-page Man-goto-page)))
1859 ) 1854 (setq major-mode 'woman-mode
1860 ;; Imenu support: 1855 mode-name "WoMan")
1861 (set (make-local-variable 'imenu-generic-expression) 1856 ;; Don't show page numbers like Man-mode does. (Online documents do
1862 ;; `make-local-variable' in case imenu not yet loaded! 1857 ;; not have pages)
1863 woman-imenu-generic-expression) 1858 (kill-local-variable 'mode-line-buffer-identification)
1864 (set (make-local-variable 'imenu-space-replacement) " ") 1859 (use-local-map woman-mode-map)
1865 ;; For reformat ... 1860 ;; Imenu support:
1866 ;; necessary when reformatting a file in its old buffer: 1861 (set (make-local-variable 'imenu-generic-expression)
1867 (setq imenu--last-menubar-index-alist nil) 1862 ;; `make-local-variable' in case imenu not yet loaded!
1868 ;; necessary to avoid re-installing the same imenu: 1863 woman-imenu-generic-expression)
1869 (setq woman-imenu-done nil) 1864 (set (make-local-variable 'imenu-space-replacement) " ")
1870 (if woman-imenu (woman-imenu)) 1865 ;; For reformat ...
1871 (setq buffer-read-only nil) 1866 ;; necessary when reformatting a file in its old buffer:
1872 (WoMan-highlight-references) 1867 (setq imenu--last-menubar-index-alist nil)
1873 (setq buffer-read-only t) 1868 ;; necessary to avoid re-installing the same imenu:
1874 (set-buffer-modified-p nil))) 1869 (setq woman-imenu-done nil)
1870 (if woman-imenu (woman-imenu))
1871 (let (buffer-read-only)
1872 (Man-highlight-references 'WoMan-xref-man-page))
1873 (set-buffer-modified-p nil)
1874 (run-mode-hooks 'woman-mode-hook))
1875 1875
1876 (defun woman-imenu (&optional redraw) 1876 (defun woman-imenu (&optional redraw)
1877 "Add a \"Contents\" menu to the menubar. 1877 "Add a \"Contents\" menu to the menubar.
1878 Optional argument REDRAW, if non-nil, forces mode line to be updated." 1878 Optional argument REDRAW, if non-nil, forces mode line to be updated."
1879 (interactive) 1879 (interactive)
1929 (substring doc 0 (string-match "\n" doc)))))) 1929 (substring doc 0 (string-match "\n" doc))))))
1930 (setq p (cdr p)))) 1930 (setq p (cdr p))))
1931 ;; Output the result: 1931 ;; Output the result:
1932 (and (apropos-print t nil) 1932 (and (apropos-print t nil)
1933 message 1933 message
1934 (message message)))) 1934 (message "%s" message))))
1935 1935
1936 1936
1937 (defun WoMan-getpage-in-background (topic) 1937 (defun WoMan-getpage-in-background (topic)
1938 "Use TOPIC to start WoMan from `Man-follow-manual-reference'." 1938 "Use TOPIC to start WoMan from `Man-follow-manual-reference'."
1939 ;; topic is a string, generally of the form "section topic" 1939 ;; topic is a string, generally of the form "section topic"
1942 (woman topic))) 1942 (woman topic)))
1943 1943
1944 (defvar WoMan-Man-start-time nil 1944 (defvar WoMan-Man-start-time nil
1945 "Used to record formatting time used by the `man' command.") 1945 "Used to record formatting time used by the `man' command.")
1946 1946
1947 (defadvice Man-getpage-in-background 1947 ;; Both advices are disabled because "a file in Emacs should not put
1948 (around Man-getpage-in-background-advice (topic) activate) 1948 ;; advice on a function in Emacs" (see Info node "(elisp)Advising
1949 "Use WoMan unless invoked outside a WoMan buffer or invoked explicitly. 1949 ;; Functions"). Counting the formatting time is useful for
1950 Otherwise use Man and record start of formatting time." 1950 ;; developping, but less applicable for daily use. The advice for
1951 (if (and (eq mode-line-format woman-mode-line-format) 1951 ;; `Man-getpage-in-background' can be discarded, because the
1952 (not (eq (caar command-history) 'man))) 1952 ;; key-binding in `woman-mode-map' has been remapped to call `woman'
1953 (WoMan-getpage-in-background topic) 1953 ;; but `man'. Michael Albinus <michael.albinus@gmx.de>
1954 ;; Initiates man processing 1954
1955 (setq WoMan-Man-start-time (current-time)) 1955 ;; (defadvice Man-getpage-in-background
1956 ad-do-it)) 1956 ;; (around Man-getpage-in-background-advice (topic) activate)
1957 1957 ;; "Use WoMan unless invoked outside a WoMan buffer or invoked explicitly.
1958 (defadvice Man-bgproc-sentinel 1958 ;; Otherwise use Man and record start of formatting time."
1959 (after Man-bgproc-sentinel-advice activate) 1959 ;; (if (and (eq major-mode 'woman-mode)
1960 ;; Terminates man processing 1960 ;; (not (eq (caar command-history) 'man)))
1961 "Report formatting time." 1961 ;; (WoMan-getpage-in-background topic)
1962 (let* ((time (current-time)) 1962 ;; ;; Initiates man processing
1963 (time (+ (* (- (car time) (car WoMan-Man-start-time)) 65536) 1963 ;; (setq WoMan-Man-start-time (current-time))
1964 (- (cadr time) (cadr WoMan-Man-start-time))))) 1964 ;; ad-do-it))
1965 (message "Man formatting done in %d seconds" time))) 1965
1966 1966 ;; (defadvice Man-bgproc-sentinel
1967 (defun WoMan-highlight-references () 1967 ;; (after Man-bgproc-sentinel-advice activate)
1968 "Highlight the references (in the SEE ALSO section) on mouse-over." 1968 ;; ;; Terminates man processing
1969 ;; Based on `Man-build-references-alist' in `man'. 1969 ;; "Report formatting time."
1970 (when (Man-find-section Man-see-also-regexp) 1970 ;; (let* ((time (current-time))
1971 (forward-line 1) 1971 ;; (time (+ (* (- (car time) (car WoMan-Man-start-time)) 65536)
1972 (let ((end (save-excursion 1972 ;; (- (cadr time) (cadr WoMan-Man-start-time)))))
1973 (Man-next-section 1) 1973 ;; (message "Man formatting done in %d seconds" time)))
1974 (point))))
1975 (back-to-indentation)
1976 (while (re-search-forward Man-reference-regexp end t)
1977 ;; Highlight reference when mouse is over it.
1978 ;; (NB: WoMan does not hyphenate!)
1979 (make-text-button (match-beginning 1) (match-end 1)
1980 'type 'woman-xref)))))
1981 1974
1982 1975
1983 ;;; Buffer handling: 1976 ;;; Buffer handling:
1984 1977
1985 (defun WoMan-previous-manpage () 1978 (defun WoMan-previous-manpage ()
2210 (setq woman-if-conditions-true 2203 (setq woman-if-conditions-true
2211 (cons (string-to-char (symbol-name woman-emulation)) '(?e ?o))) 2204 (cons (string-to-char (symbol-name woman-emulation)) '(?e ?o)))
2212 2205
2213 ;; Prepare non-underlined versions of underlined faces: 2206 ;; Prepare non-underlined versions of underlined faces:
2214 (woman-non-underline-faces) 2207 (woman-non-underline-faces)
2215 ;; Set font of `woman-symbol-face' to `woman-symbol-font' if 2208 ;; Set font of `woman-symbol' face to `woman-symbol-font' if
2216 ;; `woman-symbol-font' is well defined. 2209 ;; `woman-symbol-font' is well defined.
2217 (and woman-use-symbol-font 2210 (and woman-use-symbol-font
2218 (stringp woman-symbol-font) 2211 (stringp woman-symbol-font)
2219 (set-face-font 'woman-symbol-face woman-symbol-font 2212 (set-face-font 'woman-symbol woman-symbol-font
2220 (and (frame-live-p woman-frame) woman-frame))) 2213 (and (frame-live-p woman-frame) woman-frame)))
2221 2214
2222 ;; Set syntax and display tables: 2215 ;; Set syntax and display tables:
2223 (set-syntax-table woman-syntax-table) 2216 (set-syntax-table woman-syntax-table)
2224 (woman-set-buffer-display-table) 2217 (woman-set-buffer-display-table)
2225 2218
2226 ;; Based loosely on a suggestion by Theodore Jump: 2219 ;; Based loosely on a suggestion by Theodore Jump:
2227 (if (or woman-fill-frame 2220 (if (or woman-fill-frame
2228 (not (and (integerp woman-fill-column) (> woman-fill-column 0)))) 2221 (not (and (integerp woman-fill-column) (> woman-fill-column 0))))
2229 (setq woman-fill-column (- (frame-width) woman-default-indent))) 2222 (setq woman-fill-column (- (window-width) woman-default-indent)))
2230 2223
2231 ;; Check for preprocessor requests: 2224 ;; Check for preprocessor requests:
2232 (goto-char from) 2225 (goto-char from)
2233 (if (looking-at "'\\\\\"[ \t]*\\([a-z]+\\)") 2226 (if (looking-at "'\\\\\"[ \t]*\\([a-z]+\\)")
2234 (let ((letters (append (match-string 1) nil))) 2227 (let ((letters (append (match-string 1) nil)))
2299 (repl (if (or (= (aref esc 0) ?u) 2292 (repl (if (or (= (aref esc 0) ?u)
2300 (and (>= (length esc) 2) (= (aref esc 2) ?-))) 2293 (and (>= (length esc) 2) (= (aref esc 2) ?-)))
2301 "^" "_"))) 2294 "^" "_")))
2302 (cond (first 2295 (cond (first
2303 (replace-match repl nil t) 2296 (replace-match repl nil t)
2304 (put-text-property (1- (point)) (point) 2297 (put-text-property (1- (point)) (point) 'face 'woman-addition)
2305 'face 'woman-addition-face)
2306 (WoMan-warn 2298 (WoMan-warn
2307 "Initial vertical motion escape \\%s simulated" esc) 2299 "Initial vertical motion escape \\%s simulated" esc)
2308 (WoMan-log 2300 (WoMan-log
2309 " by TeX `%s' in woman-addition-face!" repl)) 2301 " by TeX `%s' in woman-addition-face!" repl))
2310 (t 2302 (t
2520 ;; ((looking-at "[te]") (setq c nil)) ; reject t(roff) and e(ven page) 2512 ;; ((looking-at "[te]") (setq c nil)) ; reject t(roff) and e(ven page)
2521 ((looking-at "[ntoe]") 2513 ((looking-at "[ntoe]")
2522 (setq c (memq (following-char) woman-if-conditions-true))) 2514 (setq c (memq (following-char) woman-if-conditions-true)))
2523 ;; Unrecognised letter so reject: 2515 ;; Unrecognised letter so reject:
2524 ((looking-at "[A-Za-z]") (setq c nil) 2516 ((looking-at "[A-Za-z]") (setq c nil)
2525 (WoMan-warn "%s %s -- unrecognised condition name rejected!" 2517 (WoMan-warn "%s %s -- unrecognized condition name rejected!"
2526 request (match-string 0))) 2518 request (match-string 0)))
2527 ;; Accept strings if identical: 2519 ;; Accept strings if identical:
2528 ((save-restriction 2520 ((save-restriction
2529 (narrow-to-region from woman0-if-to) 2521 (narrow-to-region from woman0-if-to)
2530 ;; String delimiter can be any non-numeric character, 2522 ;; String delimiter can be any non-numeric character,
2925 (defsubst woman-replace-match (newtext &optional face) 2917 (defsubst woman-replace-match (newtext &optional face)
2926 "Replace text matched by last search with NEWTEXT and return t. 2918 "Replace text matched by last search with NEWTEXT and return t.
2927 Set NEWTEXT in face FACE if specified." 2919 Set NEWTEXT in face FACE if specified."
2928 (woman-delete-match 0) 2920 (woman-delete-match 0)
2929 (insert-before-markers newtext) 2921 (insert-before-markers newtext)
2930 (if face (put-text-property (1- (point)) (point) 2922 (if face (put-text-property (1- (point)) (point) 'face 'woman-symbol))
2931 'face 'woman-symbol-face))
2932 t) 2923 t)
2933 2924
2934 (defun woman-special-characters (to) 2925 (defun woman-special-characters (to)
2935 "Process special character escapes \\(xx, \\[xxx] up to buffer position TO. 2926 "Process special character escapes \\(xx, \\[xxx] up to buffer position TO.
2936 \(This must be done AFTER translation, which may use special characters.)" 2927 \(This must be done AFTER translation, which may use special characters.)"
2944 (cond ((and (cddr replacement) 2935 (cond ((and (cddr replacement)
2945 (if (nthcdr 3 replacement) 2936 (if (nthcdr 3 replacement)
2946 ;; Need symbol font: 2937 ;; Need symbol font:
2947 (if woman-use-symbol-font 2938 (if woman-use-symbol-font
2948 (woman-replace-match (nth 2 replacement) 2939 (woman-replace-match (nth 2 replacement)
2949 'woman-symbol-face)) 2940 'woman-symbol))
2950 ;; Need extended font: 2941 ;; Need extended font:
2951 (if woman-use-extended-font 2942 (if woman-use-extended-font
2952 (woman-replace-match (nth 2 replacement)))))) 2943 (woman-replace-match (nth 2 replacement))))))
2953 ((cadr replacement) ; Use ASCII simulation 2944 ((cadr replacement) ; Use ASCII simulation
2954 (woman-replace-match (cadr replacement))))) 2945 (woman-replace-match (cadr replacement)))))
2969 (set-buffer standard-output) 2960 (set-buffer standard-output)
2970 (let ((i 32)) 2961 (let ((i 32))
2971 (while (< i 256) 2962 (while (< i 256)
2972 (insert (format "\\%03o " i) (string i) " " (string i)) 2963 (insert (format "\\%03o " i) (string i) " " (string i))
2973 (put-text-property (1- (point)) (point) 2964 (put-text-property (1- (point)) (point)
2974 'face 'woman-symbol-face) 2965 'face 'woman-symbol)
2975 (insert " ") 2966 (insert " ")
2976 (setq i (1+ i)) 2967 (setq i (1+ i))
2977 (when (= i 128) (setq i 160) (insert "\n")) 2968 (when (= i 128) (setq i 160) (insert "\n"))
2978 (if (zerop (% i 8)) (insert "\n"))) 2969 (if (zerop (% i 8)) (insert "\n")))
2979 )) 2970 ))
3237 3228
3238 ;;; Direct font selection: 3229 ;;; Direct font selection:
3239 3230
3240 (defconst woman-font-alist 3231 (defconst woman-font-alist
3241 '(("R" . default) 3232 '(("R" . default)
3242 ("I" . woman-italic-face) 3233 ("I" . woman-italic)
3243 ("B" . woman-bold-face) 3234 ("B" . woman-bold)
3244 ("P" . previous) 3235 ("P" . previous)
3245 ("1" . default) 3236 ("1" . default)
3246 ("2" . woman-italic-face) 3237 ("2" . woman-italic)
3247 ("3" . woman-bold-face) ; used in bash.1 3238 ("3" . woman-bold) ; used in bash.1
3248 ) 3239 )
3249 "Alist of ?roff font indicators and woman font variables and names.") 3240 "Alist of ?roff font indicators and woman font variables and names.")
3250 3241
3251 (defun woman-change-fonts () 3242 (defun woman-change-fonts ()
3252 "Process font changes." 3243 "Process font changes."
3253 ;; ***** NEEDS REVISING IF IT WORKS OK ***** 3244 ;; ***** NEEDS REVISING IF IT WORKS OK *****
3254 ;; Paragraph .LP/PP/HP/IP/TP and font .B/.BI etc. macros reset font. 3245 ;; Paragraph .LP/PP/HP/IP/TP and font .B/.BI etc. macros reset font.
3255 ;; Should .SH/.SS reset font? 3246 ;; Should .SH/.SS reset font?
3256 ;; Font size setting macros (?) should reset font. 3247 ;; Font size setting macros (?) should reset font.
3257 (let ((woman-font-alist woman-font-alist) ; for local updating 3248 (let ((font-alist woman-font-alist) ; for local updating
3258 (previous-pos (point)) 3249 (previous-pos (point))
3259 (previous-font 'default) 3250 (previous-font 'default)
3260 (current-font 'default)) 3251 (current-font 'default))
3261 (while 3252 (while
3262 ;; Find font requests, paragraph macros and font escapes: 3253 ;; Find font requests, paragraph macros and font escapes:
3283 (if notfont 3274 (if notfont
3284 () 3275 ()
3285 ;; Get font name: 3276 ;; Get font name:
3286 (or font 3277 (or font
3287 (let ((fontstring (match-string 0))) 3278 (let ((fontstring (match-string 0)))
3288 (setq font (assoc fontstring woman-font-alist) 3279 (setq font (assoc fontstring font-alist)
3289 ;; NB: woman-font-alist contains VARIABLE NAMES. 3280 ;; NB: font-alist contains VARIABLE NAMES.
3290 font (if font 3281 font (if font
3291 (cdr font) 3282 (cdr font)
3292 (WoMan-warn "Unknown font %s." fontstring) 3283 (WoMan-warn "Unknown font %s." fontstring)
3293 ;; Output this message once only per call ... 3284 ;; Output this message once only per call ...
3294 (setq woman-font-alist 3285 (setq font-alist
3295 (cons (cons fontstring 'woman-unknown-face) 3286 (cons (cons fontstring 'woman-unknown)
3296 woman-font-alist)) 3287 font-alist))
3297 'woman-unknown-face) 3288 'woman-unknown)
3298 ))) 3289 )))
3299 ;; Delete font control line or escape sequence: 3290 ;; Delete font control line or escape sequence:
3300 (cond (beg (delete-region beg (point)) 3291 (cond (beg (delete-region beg (point))
3301 (if (eq font 'previous) (setq font previous-font)))) 3292 (if (eq font 'previous) (setq font previous-font))))
3302 (woman-set-face previous-pos (point) current-font) 3293 (woman-set-face previous-pos (point) current-font)
3753 (buffer-substring start here)) 3744 (buffer-substring start here))
3754 (delete-region here (point))) 3745 (delete-region here (point)))
3755 )) 3746 ))
3756 ;; Embolden heading (point is at end of heading): 3747 ;; Embolden heading (point is at end of heading):
3757 (woman-set-face 3748 (woman-set-face
3758 (save-excursion (beginning-of-line) (point)) (point) 'woman-bold-face) 3749 (save-excursion (beginning-of-line) (point)) (point) 'woman-bold)
3759 (forward-line) 3750 (forward-line)
3760 (delete-blank-lines) 3751 (delete-blank-lines)
3761 (setq woman-left-margin woman-default-indent) 3752 (setq woman-left-margin woman-default-indent)
3762 (setq woman-prevailing-indent woman-default-indent) 3753 (setq woman-prevailing-indent woman-default-indent)
3763 (woman2-format-paragraphs to woman-left-margin)) 3754 (woman2-format-paragraphs to woman-left-margin))
3773 (woman-leave-blank-lines woman-interparagraph-distance) 3764 (woman-leave-blank-lines woman-interparagraph-distance)
3774 (setq woman-leave-blank-lines nil) 3765 (setq woman-leave-blank-lines nil)
3775 ;; Optionally embolden heading (point is at beginning of heading): 3766 ;; Optionally embolden heading (point is at beginning of heading):
3776 (if woman-bold-headings 3767 (if woman-bold-headings
3777 (woman-set-face 3768 (woman-set-face
3778 (point) (save-excursion (end-of-line) (point)) 'woman-bold-face)) 3769 (point) (save-excursion (end-of-line) (point)) 'woman-bold))
3779 (forward-line) 3770 (forward-line)
3780 (setq woman-left-margin woman-default-indent 3771 (setq woman-left-margin woman-default-indent
3781 woman-nofill nil) ; fill output lines 3772 woman-nofill nil) ; fill output lines
3782 (setq woman-prevailing-indent woman-default-indent) 3773 (setq woman-prevailing-indent woman-default-indent)
3783 (woman2-format-paragraphs to woman-left-margin)) 3774 (woman2-format-paragraphs to woman-left-margin))
4546 ))))) 4537 )))))
4547 nil) ; for woman-file-readable-p etc. 4538 nil) ; for woman-file-readable-p etc.
4548 4539
4549 (provide 'woman) 4540 (provide 'woman)
4550 4541
4542 ;;; arch-tag: eea35e90-552f-4712-a94b-d9ffd3db7651
4551 ;;; woman.el ends here 4543 ;;; woman.el ends here