mirrored from git://git.sv.gnu.org/emacs.git
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathwoman.el
4590 lines (4101 loc) · 172 KB
/
woman.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; woman.el --- browse UN*X manual pages `wo (without) man' -*- lexical-binding: t; -*-
;; Copyright (C) 2000-2025 Free Software Foundation, Inc.
;; Author: Francis J. Wright <F.J.Wright@qmul.ac.uk>
;; Maintainer: emacs-devel@gnu.org
;; Keywords: help, unix
;; Adapted-By: Eli Zaretskii <eliz@gnu.org>
;; Old-Version: 0.551
;; URL: http://centaur.maths.qmul.ac.uk/Emacs/WoMan/
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; WoMan implements a subset of the formatting performed by the Emacs
;; `man' (or `manual-entry') command to format a UN*X manual `page'
;; for display, but without calling any external programs. It is
;; intended to emulate the whole of the -man macro package, plus those
;; ?roff requests that are most commonly used in man pages. However,
;; the emulation is modified to include the reformatting done by the
;; Emacs `man' command. No hyphenation is performed.
;; Note that `M-x woman' doesn’t yet support the latest features of
;; modern man pages, so we recommend using `M-x man' if that is
;; available on your system.
;; Advantages
;; Much more direct, does not require any external programs.
;; Supports completion on man page names.
;; Disadvantages
;; Not a complete emulation. Currently no support for eqn or tbl.
;; Slightly slower for large man pages (but usually faster for
;; small- and medium-size pages).
;; This browser works quite well on simple well-written man files. It
;; works less well on idiosyncratic files that `break the rules' or
;; use the more obscure ?roff requests directly. Current test results
;; are available in the file woman.status.
;; WoMan supports the use of compressed man files via
;; `auto-compression-mode' by turning it on if necessary. But you may
;; need to adjust the user option `woman-file-compression-regexp'.
;; Read on for (currently) the only documentation for WoMan!
;; See also the documentation for the WoMan interactive commands and
;; user option variables, all of which begin with the prefix `woman-'.
;; This can be done most easily by loading WoMan and then running the
;; command `woman-mini-help', or selecting the WoMan menu option `Mini
;; Help' when WoMan is running.
;; WoMan is still under development! Please let me know what doesn't
;; work -- I am adding and improving functionality as testing shows
;; that it is necessary. See below for guidance on reporting bugs.
;; Recommended use
;; ===============
;; Either (1 -- *RECOMMENDED*): If the `MANPATH' environment
;; variable is set then WoMan will use it; otherwise you may need to
;; reset the Lisp variable `woman-manpath', and you may also want to
;; set the Lisp variable `woman-path'. Please see the online
;; documentation for these variables. Now you can execute the
;; extended command `woman', enter or select a manual entry topic,
;; using completion, and if necessary select a filename, using
;; completion. By default, WoMan suggests the word nearest to the
;; cursor in the current buffer as the topic.
;; Or (2): Execute the extended command `woman-find-file' and enter a
;; filename, using completion. This mode of execution may be useful
;; for temporary files outside the standard UN*X manual directory
;; structure.
;; Or (3): Put this in your init file:
;; (with-eval-after-load 'dired
;; (keymap-set dired-mode-map "W" 'woman-dired-find-file))
;; and open the directory containing the man page file using Dired,
;; put the cursor on the file, and press `W'.
;; In each case, the result should (!) be a buffer in Man mode showing
;; a formatted manual entry. When called from WoMan, Man mode should
;; work as advertised, but modified where necessary in the context of
;; WoMan. (However, `Man' will still invoke the standard Emacs
;; manual-browsing facility rather than `WoMan' -- this is
;; intentional!)
;; (By default, WoMan will automatically define the Dired keys "W" and
;; "w" when it loads, but only if they are not already defined. This
;; behavior is controlled by the user option `woman-dired-keys'.
;; Note that the `dired-x' (dired extra) package binds
;; `dired-copy-filename-as-kill' to the key "w" (as pointed out by Jim
;; Davidson), although "W" appears to be really unused. The `dired-x'
;; package will over-write the WoMan binding to "w", whereas (by
;; default) WoMan will not overwrite the `dired-x' binding.)
;; Using the word at point as the default topic
;; ============================================
;; The `woman' command uses the word nearest to point in the current
;; buffer as the default topic to look up if it matches the name of a
;; manual page installed on the system. The default topic can also be
;; used without confirmation by setting the user-option
;; `woman-use-topic-at-point' to t; thanks to Benjamin Riefenstahl for
;; suggesting this functionality.
;; The variable `woman-use-topic-at-point' can be rebound locally,
;; which may be useful to provide special private key bindings, e.g.
;; (keymap-global-set "C-c w"
;; (lambda ()
;; (interactive)
;; (let ((woman-use-topic-at-point t))
;; (woman)))))
;; Customization, Hooks and Imenu
;; ==============================
;; WoMan supports the GNU Emacs customization facility, and puts
;; a customization group called `woman' in the `help' group under the
;; top-level `emacs' group.
;; WoMan currently runs two hooks: `woman-pre-format-hook' immediately
;; before formatting a buffer and `woman-post-format-hook' immediately
;; after formatting a buffer. These hooks can be used for special
;; customizations that require code to be executed, etc., although
;; most customization should be possible by setting WoMan user option
;; variables, e.g. in `.emacs' and should NOT require the use of the
;; hooks. `woman-pre-format-hook' might be appropriate for face
;; customization, whereas `woman-post-format-hook' might be
;; appropriate for installing a dynamic menu using `imenu' (although
;; it is better to use the built-in WoMan imenu support).
;; The WoMan menu provides an option to make a contents menu for the
;; current man page (using imenu). Alternatively, if you set the
;; variable `woman-imenu' to t then WoMan will do it automatically
;; for every man page. The menu title is the value of the variable
;; `woman-imenu-title', which is "CONTENTS" by default. By default,
;; the menu shows manual sections and subsections, but you can change
;; this by changing the value of `woman-imenu-generic-expression'.
;; This facility is not yet widely tested and may be fooled by obscure
;; man pages that `break the rules'.
;; WoMan is configured not to replace spaces in an imenu *Completion*
;; buffer. For further documentation of the use of imenu, such as
;; menu sorting, see the source file imenu.el, which is distributed
;; with GNU Emacs.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Howard Melman made (essentially) the following suggestions, which
;; are slightly different from the expression that I currently use.
;; You may prefer one of Howard's suggestions, which I think assume
;; that `case-fold-search' is t (which it is by default):
;; (setq woman-imenu-generic-expression
;; '((nil "^\\( \\)?\\([A-Z][A-Z ]+[A-Z]\\)[ \t]*$" 2)))
;; will give support for .SH and .SS, though it won't show the heading
;; name hierarchy. If you just want .SH in the imenu then use:
;; (setq woman-imenu-generic-expression
;; '((nil "^\\([A-Z][A-Z ]+[A-Z]\\)[ \t]*$" 1)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Vertical spacing and blank lines
;; ================================
;; The number of consecutive blank lines in the formatted buffer
;; should be either 0 or 1. A blank line should leave a space like
;; .sp 1 (p. 14). Current policy is to output vertical space only
;; immediately before text is output.
;; Horizontal and vertical spacing and resolution
;; ==============================================
;; WoMan currently assumes 10 characters per inch horizontally, hence
;; a horizontal resolution of 24 basic units, and 5 lines per inch
;; vertically, hence a vertical resolution of 48 basic units. (nroff
;; uses 240 per inch).
;; The *WoMan-Log* buffer
;; ======================
;; This is modeled on the byte-compiler. It logs all files formatted
;; by WoMan, and if WoMan finds anything that it cannot handle then it
;; writes a warning to this buffer. If the variable `woman-show-log'
;; is non-nil (by default it is nil) then WoMan automatically
;; displays this buffer. Many WoMan warnings can be completely
;; ignored, because they are reporting the fact that WoMan has ignored
;; requests that it is correct to ignore. In some future version this
;; level of paranoia will be reduced, but not until WoMan is more
;; reliable. At present, all warnings should be treated with some
;; suspicion. Uninterpreted escape sequences are also logged (in some
;; cases).
;; Uninterpreted ?roff requests can optionally be left in the
;; formatted buffer to indicate precisely where they occur by
;; resetting the variable `woman-ignore' to nil (by default it is
;; t).
;; Automatic initiation of woman decoding
;; (Probably not a good idea. If you use it, be careful!)
;; Put something like this in your .emacs. The call to
;; set-visited-file-name is to avoid font-locking triggered by
;; automatic major mode selection.
;; (autoload 'woman-decode-region "woman")
;; (setq format-alist
;; (cons
;; '(man "UN*X man-page source format" "\\.\\(TH\\|ig\\) "
;; woman-decode-region nil nil
;; (lambda (arg)
;; set-visited-file-name
;; (file-name-sans-extension buffer-file-name)))))
;; format-alist))
;; Reporting Bugs
;; ==============
;; If WoMan fails completely, or formats a file incorrectly
;; (i.e. obviously wrongly or significantly differently from man) or
;; inelegantly, then please
;; (a) check that you are running the latest version of woman.el
;; available from my web site (see above),
;; (b) check that the problem is not already described in the file
;; woman.status, also available from my web site.
;; If both of the above are true then please email me the entry from
;; the *WoMan-Log* buffer relating to the problem file, together with
;; a brief description of the problem. Please indicate where you got
;; the source file from, but do not send it to me unless I ask you to!
;; Thanks. (There is at present no automated bug-reporting facility
;; for WoMan.)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NOTE:
;; CASE-DEPENDENCE OF FILENAMES. By default, WoMan ignores case in
;; file pathnames only when it seems appropriate. MS-Windows users
;; who want complete case independence should set the NTEmacs variable
;; `w32-downcase-file-names' to t and use all lower case when
;; setting WoMan file paths.
;; (1) INCOMPATIBLE CHANGE! WoMan no longer uses a persistent topic
;; cache by default. (It caused too much confusion!) Explicitly set
;; the variable `woman-cache-filename' to save the cache between Emacs
;; sessions. This is recommended only if the command `woman' is too
;; slow the first time that it is run in an Emacs session, while it
;; builds its cache in main memory, which MAY be VERY slow.
;; (2) The user option `woman-cache-level' controls the amount of
;; information cached (in main memory and, optionally, saved to disc).
;; (3) UPDATING THE CACHE. A prefix argument always causes the
;; `woman' command (only) to rebuild its topic cache, and to re-save
;; it to `woman-cache-filename' if this variable has a non-nil value.
;; This is necessary if the NAMES (not contents) of any of the
;; directories or files in the paths specified by `woman-manpath' or
;; `woman-path' change. If WoMan user options that affect the cache
;; are changed then WoMan will automatically update its cache file on
;; disc (if one is in use) the next time it is run in a new Emacs
;; session.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TO DO
;; =====
;; Reconsider case sensitivity of file names.
;; MUST PROCESS .if, .nr IN ORDER ENCOUNTERED IN FILE! (rcsfile, mf).
;; Allow general delimiter in `\v', cf. `\h'.
;; Improve major-mode documentation.
;; Pre-process conditionals in macro bodies if possible for speed?
;; Emulate more complete preprocessor support for tbl (.TS/.TE)
;; Emulate some preprocessor support for eqn (.EQ/.EN)
;; Re-write filling and adjusting code!
;; Allow word wrap at comma (for long option lists)?
;; Buffer list handling not quite right.
;; Make 10 or 12 pitch (cpi) optional -- 12 => ll = 78
;; Use unpaddable space for tabbing?
;; Tidy up handling of fonts when filling and adjusting
;; -- see text/text properties?
;; Improve speed
;; Add font-lock support (for quoted strings, etc.)?
;; Optionally save large files in enriched format?
;; Add apropos facility by searching NAME (?) entry in man files?
;; Documentation -- optional auto-display of formatted WoMan man page?
;; Implement a bug reporter?
;; Support diversion and traps (to some extent) - for Tcl/tk pages?
;; Add a menu of WoMan buffers?
;; Fix .fc properly?
;; Implementation strategy [this description is now well out of date!]
;; -- three main passes, each to process respectively:
;; 1) non-breaking `.' requests including font macros
;; 2) \ escape sequences, mainly special characters and font changes
;; 3) breaking `.' requests, mainly filling and justification
;; For each pass, a control function finds and pre-processes the
;; escape or request and then calls the appropriate function to
;; perform the required formatting. Based originally on enriched.el
;; and format.el.
;; The background information that made this project possible is
;; freely available courtesy of Bell Labs from
;; http://cm.bell-labs.com/7thEdMan/
;; Acknowledgments
;; ===============
;; For Heather, Kathryn and Madelyn, the women in my life
;; (although they will probably never use it)!
;; I also thank the following for helpful suggestions, bug reports,
;; code fragments, general interest, etc.:
;; Jari Aalto <jari.aalto@cs.tpu.fi>
;; Dean Andrews <dean@dra.com>
;; Juanma Barranquero <lekktu@gmail.com>
;; Karl Berry <kb@cs.umb.edu>
;; Jim Chapman <jchapman@netcomuk.co.uk>
;; Kin Cho <kin@neoscale.com>
;; Frederic Corne <frederic.corne@erli.fr>
;; Peter Craft <craft@alacritech.com>
;; Charles Curley <ccurley@trib.com>
;; Jim Davidson <jdavidso@teknowledge.com>
;; Kevin D'Elia <Kevin.DElia@mci.com>
;; John Fitch <jpff@maths.bath.ac.uk>
;; Hans Frosch <jwfrosch@rish.b17c.ingr.com>
;; Guy Gascoigne-Piggford <ggp@informix.com>
;; Brian Gorka <gorkab@sanchez.com>
;; Nicolai Henriksen <nhe@lyngso-industri.dk>
;; Thomas Herchenroeder <the@software-ag.de>
;; Alexander Hinds <ahinds@thegrid.net>
;; Stefan Hornburg <sth@hacon.de>
;; Theodore Jump <tjump@cais.com>
;; David Kastrup <dak@gnu.org>
;; Paul Kinnucan <paulk@mathworks.com>
;; Jonas Linde <jonas@init.se>
;; Andrew McRae <andrewm@optimation.co.nz>
;; Howard Melman <howard@silverstream.com>
;; Dennis Pixton <dennis@math.binghamton.edu>
;; T. V. Raman <raman@Adobe.COM>
;; Bruce Ravel <bruce.ravel@nist.gov>
;; Benjamin Riefenstahl <benny@crocodial.de>
;; Kevin Ruland <kruland@seistl.com>
;; Tom Schutter <tom@platte.com>
;; Wei-Xue Shi <wxshi@ma.neweb.ne.jp>
;; Fabio Somenzi <fabio@joplin.colorado.edu>
;; Karel Sprenger <ks@ic.uva.nl>
;; Chris Szurgot <szurgot@itribe.net>
;; Paul A. Thompson <pat@po.cwru.edu>
;; Arrigo Triulzi <arrigo@maths.qmw.ac.uk>
;; Geoff Voelker <voelker@cs.washington.edu>
;; Eli Zaretskii <eliz@gnu.org>
;;; Code:
(eval-when-compile (require 'cl-lib))
(require 'man)
(define-button-type 'WoMan-xref-man-page
:supertype 'Man-abstract-xref-man-page
'func (lambda (arg)
(woman
;; `woman' cannot deal with arguments that contain a
;; section name, like close(2), so strip the section name.
(if (string-match Man-reference-regexp arg)
(substring arg 0 (match-end 1))
arg))))
(eval-when-compile ; to avoid compiler warnings
(require 'cl-lib)
(require 'dired)
(require 'apropos))
(defun woman-parse-colon-path (paths)
"Explode search path string PATHS into a list of directory names.
Allow Cygwin colon-separated search paths on Microsoft platforms.
Replace null components by calling `woman-parse-man.conf'.
As a special case, if PATHS is nil then replace it by calling
`woman-parse-man.conf'."
;; Based on suggestions by Jari Aalto and Eli Zaretskii.
;; parse-colon-path returns nil for a null path component and
;; an empty substring of MANPATH denotes the default list.
(if (memq system-type '(windows-nt ms-dos))
(cond ((null paths)
(mapcar #'woman-Cyg-to-Win (woman-parse-man.conf)))
((string-search ";" paths)
;; Assume DOS-style path-list...
(mapcan ; splice list into list
(lambda (x)
(if x
(list x)
(mapcar #'woman-Cyg-to-Win (woman-parse-man.conf))))
(parse-colon-path paths)))
((string-match-p "\\`[a-zA-Z]:" paths)
;; Assume single DOS-style path...
(list paths))
(t
;; Assume UNIX/Cygwin-style path-list...
(mapcan ; splice list into list
(lambda (x)
(mapcar #'woman-Cyg-to-Win
(if x (list x) (woman-parse-man.conf))))
(let ((path-separator ":"))
(parse-colon-path paths)))))
;; Assume host-default-style path-list...
(mapcan ; splice list into list
(lambda (x) (if x (list x) (woman-parse-man.conf)))
(parse-colon-path (or paths "")))))
(defun woman-Cyg-to-Win (file)
"Convert an absolute filename FILE from Cygwin to Windows form."
;; MANPATH_MAP conses are not converted since they presumably map
;; Cygwin to Cygwin form.
(if (consp file)
file
;; Code taken from w32-symlinks.el
(if (eq (aref file 0) ?/)
;; Try to use Cygwin mount table via `cygpath.exe'.
(condition-case nil
(with-temp-buffer
;; cygpath -m file
(call-process "cygpath" nil t nil "-m" file)
(buffer-substring 1 (buffer-size)))
(error
;; Assume no `cygpath' program available.
;; Hack /cygdrive/x/ or /x/ or (obsolete) //x/ to x:/
(when (string-match "\\`\\(/cygdrive\\|/\\)?/./" file)
(if (match-beginning 1) ; /cygdrive/x/ or //x/ -> /x/
(setq file (substring file (match-end 1))))
(aset file 0 (aref file 1)) ; /x/ -> xx/
(aset file 1 ?:)) ; xx/ -> x:/
file))
file)))
;;; User options:
;; NB: Group identifiers must be lowercase!
(defgroup woman nil
"Browse UNIX manual pages `wo (without) man'."
:tag "WoMan"
:link '(custom-manual "(woman) Top")
:link '(emacs-commentary-link :tag "Commentary" "woman.el")
:group 'help)
(defcustom woman-show-log nil
"If non-nil then show the *WoMan-Log* buffer if appropriate.
I.e. if any warning messages are written to it. Default is nil."
:type 'boolean
:group 'woman)
(defcustom woman-pre-format-hook nil
"Hook run by WoMan immediately before formatting a buffer.
Change only via `Customization' or the function `add-hook'."
:type 'hook
:group 'woman)
(defcustom woman-post-format-hook nil
"Hook run by WoMan immediately after formatting a buffer.
Change only via `Customization' or the function `add-hook'."
:type 'hook
:group 'woman)
;; Interface options
(defgroup woman-interface nil
"Interface options for browsing UNIX manual pages `wo (without) man'."
:tag "WoMan Interface"
:group 'woman)
(defcustom woman-man.conf-path
(let ((path '("/usr/lib" "/etc")))
(cond ((eq system-type 'windows-nt)
(mapcar #'woman-Cyg-to-Win path))
((eq system-type 'darwin)
(cons "/usr/share/misc" path))
(t path)))
"List of dirs to search and/or files to try for man config file.
A trailing separator (`/' for UNIX etc.) on directories is
optional, and the filename is used if a directory specified is
the first to start with \"man\" and has an extension starting
with \".conf\". If MANPATH is not set but a config file is found
then it is parsed instead to provide a default value for
`woman-manpath'."
:type '(repeat string)
:group 'woman-interface)
(defun woman-parse-man.conf ()
"Parse if possible configuration file for man command.
Used only if MANPATH is not set or contains null components.
Look in `woman-man.conf-path' and return a value for `woman-manpath'.
Concatenate data from all lines in the config file of the form
MANPATH /usr/man
or
MANDATORY_MANPATH /usr/man
or
OPTIONAL_MANPATH /usr/man
or
MANPATH_MAP /opt/bin /opt/man"
;; Functionality suggested by Charles Curley.
(let ((path woman-man.conf-path)
file manpath)
(while (and
path
(not (and
(file-readable-p (setq file (car path)))
;; If not a file then find the file:
(or (not (file-directory-p file))
(and
(setq file
(directory-files file t "\\`man.*\\.conf[a-z]*\\'" t))
(file-readable-p (setq file (car file)))))
;; Parse the file -- if no MANPATH data ignore it:
(with-temp-buffer
(insert-file-contents file)
(while (re-search-forward
;; `\(?: ... \)' is a "shy group"
"\
^[ \t]*\\(?:\\(?:MANDATORY_\\|OPTIONAL_\\)?MANPATH[ \t]+\\(\\S-+\\)\\|\
MANPATH_MAP[ \t]+\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\)" nil t)
(cl-pushnew (if (match-beginning 1)
(match-string 1)
(cons (match-string 2)
(match-string 3)))
manpath :test #'equal))
manpath))
))
(setq path (cdr path)))
(nreverse manpath)))
;; Autoload so set-locale-environment can operate on it.
;;;###autoload
(defcustom woman-locale nil
"String specifying a manual page locale, or nil.
If a manual page is available in the specified locale
\(e.g. \"sv_SE.ISO8859-1\"), it will be offered in preference to the
default version. Normally, `set-locale-environment' sets this at startup."
:type '(choice string (const nil))
:group 'woman-interface
:version "23.1")
;; FIXME Is this a sensible list of alternatives?
(defun woman-expand-locale (locale)
"Expand a locale into a list suitable for man page lookup.
Expands a locale of the form LANGUAGE_TERRITORY.CHARSET into the list:
LANGUAGE_TERRITORY.CHARSET LANGUAGE_TERRITORY LANGUAGE.CHARSET LANGUAGE.
The TERRITORY and CHARSET portions may be absent."
(string-match "\\([^._]*\\)\\(_[^.]*\\)?\\(\\..*\\)?" locale)
(let ((lang (match-string 1 locale))
(terr (match-string 2 locale))
(charset (match-string 3 locale)))
(delq nil (list locale
(and charset terr (concat lang terr))
(and charset terr (concat lang charset))
(if (or charset terr) lang)))))
(defun woman-manpath-add-locales (manpath)
"Add locale-specific subdirectories to the elements of MANPATH.
MANPATH is a list of the form of `woman-manpath'. Returns a list
with those locale-specific subdirectories specified by the action
of `woman-expand-locale' on `woman-locale' added, where they exist."
(if (zerop (length woman-locale))
manpath
(let ((subdirs (woman-expand-locale woman-locale))
lst dir)
(dolist (elem manpath (nreverse lst))
(dolist (sub subdirs)
(when (file-directory-p
(setq dir
;; Use f-n-a-d because parse-colon-path does.
(file-name-as-directory
(expand-file-name sub (substitute-in-file-name
(if (consp elem)
(cdr elem)
elem))))))
(cl-pushnew (if (consp elem)
(cons (car elem) dir)
dir)
lst :test #'equal)))
;; Non-locale-specific has lowest precedence.
(cl-pushnew elem lst :test #'equal)))))
(defcustom woman-manpath
;; Locales could also be added in woman-expand-directory-path.
(or (woman-manpath-add-locales
(woman-parse-colon-path (getenv "MANPATH")))
'("/usr/man" "/usr/share/man" "/usr/local/man"))
"List of DIRECTORY TREES to search for UN*X manual files.
Each element should be the name of a directory that contains
subdirectories of the form `man?', or more precisely subdirectories
selected by the value of `woman-manpath-man-regexp'. Non-directory
and unreadable files are ignored.
Elements can also be a cons cell indicating a mapping from PATH
to manual trees: if such an element's car is equal to a path
element of the environment variable PATH, the cdr of the cons
cell is included in the directory tree search.
If not set then the environment variable MANPATH is used. If no such
environment variable is found, the default list is determined by
consulting the man configuration file if found, which is determined by
the user option `woman-man.conf-path'. An empty substring of MANPATH
denotes the default list.
Any environment variables (names must have the UN*X-style form $NAME,
e.g. $HOME, $EMACSDATA, $emacs_dir) are evaluated first but each
element must evaluate to a SINGLE directory name. Trailing `/'s are
ignored. (Specific directories in `woman-path' are also searched.)
Microsoft platforms:
I recommend including drive letters explicitly, e.g.
(\"C:/Cygwin/usr/man/\" \"C:/Cygwin/usr/local/man\").
The MANPATH environment variable may be set using DOS semi-colon-
separated or UN*X/Cygwin colon-separated syntax (but not mixed)."
:type '(repeat (choice string (cons string string)))
:version "23.1" ; added woman-manpath-add-locales
:group 'woman-interface)
(defcustom woman-manpath-man-regexp "[Mm][Aa][Nn]"
"Regexp to match man directories UNDER `woman-manpath' directories.
These normally have names of the form `man?'. Its default value is
\"[Mm][Aa][Nn]\", which is case-insensitive mainly for the benefit of
Microsoft platforms. Its purpose is to avoid `cat?', `.', `..', etc."
;; Based on a suggestion by Wei-Xue Shi.
:type 'regexp
:group 'woman-interface)
(defcustom woman-path
(if (eq system-type 'ms-dos) '("$DJDIR/info" "$DJDIR/man/cat[1-9onlp]"))
"List of SPECIFIC DIRECTORIES to search for UN*X manual files.
For example
(\"/emacs/etc\").
These directories are searched in addition to the directory trees
specified in `woman-manpath'. Each element should be a directory
string or nil, which represents the current directory when the path is
expanded and cached. However, the last component (only) of each
directory string is treated as a regexp \(Emacs, not shell) and the
string is expanded into a list of matching directories. Non-directory
and unreadable files are ignored. The default value is nil.
Any environment variables (which must have the UN*X-style form $NAME,
e.g. $HOME, $EMACSDATA, $emacs_dir) are evaluated first but each
element must evaluate to a SINGLE directory name (regexp, see above).
For example
(\"$EMACSDATA\") [or equivalently (\"$emacs_dir/etc\")].
Trailing `/'s are discarded. (The directory trees in `woman-manpath'
are also searched.) On Microsoft platforms I recommend including
drive letters explicitly."
:type '(repeat (choice string (const nil)))
:group 'woman-interface)
(defcustom woman-cache-level 2
"The level of topic caching.
1 - cache only the topic and directory lists
(the only level before version 0.34 - only for compatibility);
2 - cache also the directories for each topic
(faster, without using much more memory);
3 - cache also the actual filenames for each topic
(fastest, but uses twice as much memory).
The default value is currently 2, a good general compromise.
If the `woman' command is slow to find files then try 3, which may be
particularly beneficial with large remote-mounted man directories.
Run the `woman' command with a prefix argument or delete the cache
file `woman-cache-filename' for a change to take effect.
\(Values < 1 behave like 1; values > 3 behave like 3.)"
:type '(choice (const :tag "Minimal" 1)
(const :tag "Default" 2)
(const :tag "Maximal" 3))
:group 'woman-interface)
(defcustom woman-cache-filename nil
"The full pathname of the WoMan directory and topic cache file.
It is used to save and restore the cache between sessions. This is
especially useful with remote-mounted man page files! The default
value of nil suppresses this action. The `standard' non-nil
filename is \"~/.wmncach.el\". Remember that a prefix argument forces
the `woman' command to update and re-write the cache."
:type '(choice (const :tag "None" nil)
(const :tag "~/.wmncach.el" "~/.wmncach.el")
file)
:group 'woman-interface)
(defcustom woman-dired-keys t
"List of `dired' mode keys to define to run WoMan on current file.
E.g. (\"w\" \"W\"), or any non-null atom to automatically define
\"w\" and \"W\" if they are unbound, or nil to do nothing.
Default is t."
:type '(choice (const :tag "None" nil)
(repeat string)
(other :tag "Auto" t))
:group 'woman-interface)
(defcustom woman-imenu-generic-expression
'((nil "\n\\([A-Z].*\\)" 1) ; SECTION, but not TITLE
("*Subsections*" "^ \\([A-Z].*\\)" 1))
"Imenu support for Sections and Subsections.
An alist with elements of the form (MENU-TITLE REGEXP INDEX) --
see the documentation for `imenu-generic-expression'."
:type '(alist :key-type (choice :tag "Title" (const nil) string)
:value-type (group (choice (regexp :tag "Regexp")
function)
integer))
:group 'woman-interface)
(defcustom woman-imenu nil
"If non-nil then WoMan adds a Contents menu to the menubar.
It does this by calling `imenu-add-to-menubar'. Default is nil."
:type 'boolean
:group 'woman-interface)
(defcustom woman-imenu-title "CONTENTS"
"The title to use if WoMan adds a Contents menu to the menubar.
Default is \"CONTENTS\"."
:type 'string
:group 'woman-interface)
(defcustom woman-use-topic-at-point-default nil
;; `woman-use-topic-at-point' may be let-bound when woman is loaded,
;; in which case its global value does not get defined.
;; `woman-file-name' sets it to this value if it is unbound.
"Default value for `woman-use-topic-at-point'."
:type '(choice (const :tag "Yes" t)
(const :tag "No" nil))
:group 'woman-interface)
(defcustom woman-use-topic-at-point woman-use-topic-at-point-default
"Control use of the word at point as the default topic.
If non-nil the `woman' command uses the word at point automatically,
without interactive confirmation, if it exists as a topic."
:type '(choice (const :tag "Yes" t)
(const :tag "No" nil))
:group 'woman-interface)
(defvar woman-file-regexp nil
"Regexp used to select (possibly compressed) man source files, e.g.
\"\\.\\([0-9lmnt]\\w*\\)\\(\\.\\(g?z\\|bz2\\|xz\\)\\)?\\\\='\".
Built automatically from the customizable user options
`woman-uncompressed-file-regexp' and `woman-file-compression-regexp'.")
(defvar woman-uncompressed-file-regexp) ; for the compiler
(defvar woman-file-compression-regexp) ; for the compiler
(defun woman-set-file-regexp (symbol value)
"Bind SYMBOL to VALUE and set `woman-file-regexp' as per user customizations.
Used as :set cookie by Customize when customizing the user options
`woman-uncompressed-file-regexp' and `woman-file-compression-regexp'."
(set-default symbol value)
(and (boundp 'woman-uncompressed-file-regexp)
(boundp 'woman-file-compression-regexp)
(setq woman-file-regexp
(concat woman-uncompressed-file-regexp
"\\("
(substring woman-file-compression-regexp 0 -2)
"\\)?\\'"))))
(defcustom woman-uncompressed-file-regexp
"\\.\\([0-9lmnt]\\w*\\)" ; disallow no extension
"Do not change this unless you are sure you know what you are doing!
Regexp used to select man source files (ignoring any compression extension).
The SysV standard man pages use two character suffixes, and this is
becoming more common in the GNU world. For example, the man pages
in the ncurses package include `toe.1m', `form.3x', etc.
Note: an optional compression regexp will be appended, so this regexp
MUST NOT end with any kind of string terminator such as $ or \\\\='."
:type 'regexp
:set #'woman-set-file-regexp
:group 'woman-interface)
(defcustom woman-file-compression-regexp
"\\.\\(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\\\\|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 #'woman-set-file-regexp
:group 'woman-interface)
(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
:group 'woman-interface)
;; Formatting options
(defgroup woman-formatting nil
"Formatting options for browsing UNIX manual pages `wo (without) man'."
:tag "WoMan Formatting"
:group 'woman)
;; This could probably be 80 to match 'Man-width'.
(defcustom woman-fill-column 70
"Right margin for formatted text -- default is 70."
:type 'natnum
:group 'woman-formatting
:version "29.1")
(defcustom woman-fill-frame nil
;; Based loosely on a suggestion by Theodore Jump:
"If non-nil then most of the window width is used."
:type 'boolean
:group 'woman-formatting)
(defcustom woman-default-indent 5
"Default prevailing indent set by -man macros -- default is 5.
Set this variable to 7 to emulate GNU man formatting."
:type 'integer
:group 'woman-formatting)
(defcustom woman-bold-headings t
"If non-nil then embolden section and subsection headings. Default is t.
Heading emboldening is NOT standard `man' behavior."
:type 'boolean
:group 'woman-formatting)
(defcustom woman-ignore t
"If non-nil then unrecognized requests etc. are ignored. Default is t.
This gives the standard ?roff behavior. If nil then they are left in
the buffer, which may aid debugging."
:type 'boolean
:group 'woman-formatting)
(defcustom woman-preserve-ascii t
"If non-nil, preserve ASCII characters in the WoMan buffer.
Otherwise, to save time, some backslashes and spaces may be
represented differently (as the values of the variables
`woman-escaped-escape-char' and `woman-unpadded-space-char'
respectively) so that the buffer content is strictly wrong even though
it should display correctly. This should be irrelevant unless the
buffer text is searched, copied or saved to a file."
;; This option should probably be removed!
:type 'boolean
:group 'woman-formatting)
(defcustom woman-emulation 'nroff
"WoMan emulation, currently either nroff or troff. Default is nroff.
Troff emulation is experimental and largely untested.
\(Add groff later?)"
:type '(choice (const nroff) (const troff))
:group 'woman-formatting)
;; Faces:
(defgroup woman-faces nil
"Face options for browsing UNIX manual pages `wo (without) man'."
:tag "WoMan Faces"
:group 'woman
:group 'faces)
(defcustom woman-fontify
(or (display-color-p)
(display-graphic-p)
(display-color-p))
"If non-nil then WoMan assumes that face support is available.
It defaults to a non-nil value if the display supports either colors
or different fonts."
:type 'boolean
:group 'woman-faces)
(defface woman-italic
'((t :inherit italic))
"Face for italic font in man pages."
:group 'woman-faces)
(defface woman-bold
'((t :inherit bold))
"Face for bold font in man pages."
:group 'woman-faces)
(defface woman-unknown
'((t :inherit font-lock-warning-face))
"Face for all unknown fonts in man pages."
:group 'woman-faces)
(defface woman-addition
'((t :inherit font-lock-builtin-face))
"Face for all WoMan additions to man pages."
:group 'woman-faces)
(defun woman-default-faces ()
"Set foreground colors of italic and bold faces to their default values."
(declare (obsolete "customize the woman-* faces instead." "24.4"))
(interactive)
(face-spec-set 'woman-italic (face-user-default-spec 'woman-italic))
(face-spec-set 'woman-bold (face-user-default-spec 'woman-bold)))
(defun woman-monochrome-faces ()
"Set foreground colors of italic and bold faces to that of the default face.
This is usually either black or white."
(declare (obsolete "customize the woman-* faces instead." "24.4"))
(interactive)
(set-face-foreground 'woman-italic 'unspecified)
(set-face-foreground 'woman-bold 'unspecified))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Experimental font support, initially only for MS-Windows.
(defconst woman-font-support
(eq window-system 'w32) ; Support X later!
"If non-nil then non-ASCII characters and symbol font supported.")
(defun woman-select-symbol-fonts (fonts)
"Select symbol fonts from a list FONTS of font name strings."
(let (symbol-fonts)
;; With NTEmacs 20.5, the PATTERN option to `x-list-fonts' does
;; not seem to work and fonts may be repeated, so ...
(dolist (font fonts)
(and (string-match-p "-Symbol-" font)
(not (member font symbol-fonts))
(setq symbol-fonts (cons font symbol-fonts))))
symbol-fonts))
(declare-function x-list-fonts "xfaces.c"
(pattern &optional face frame maximum width))
(when woman-font-support
(make-face 'woman-symbol)
;; Set the symbol font only if `woman-use-symbol-font' is true, to
;; avoid unnecessarily upsetting the line spacing in NTEmacs 20.5!
(defcustom woman-use-extended-font t
"If non-nil then may use non-ASCII characters from the default font."
:type 'boolean
:group 'woman-faces)
(defcustom woman-use-symbol-font nil
"If non-nil then may use the symbol font.
It is off by default, mainly because it may change the line spacing
\(in NTEmacs 20.5)."
:type 'boolean
:group 'woman-faces)
(defconst woman-symbol-font-list
(or (woman-select-symbol-fonts (x-list-fonts "*" 'default))
(woman-select-symbol-fonts (x-list-fonts "*")))
"Symbol font(s), preferably same size as default when WoMan was loaded.")
(defcustom woman-symbol-font (car woman-symbol-font-list)
"A string describing the symbol font to use for special characters.
It should be compatible with, and the same size as, the default text font.
Under MS-Windows, the default is
\"-*-Symbol-normal-r-*-*-*-*-96-96-p-*-ms-symbol\"."
:type `(choice
,@(mapcar (lambda (x) (list 'const x))
woman-symbol-font-list)
string)