Merge pull request #329823 from ExpidusOS/fix/pkgsllvm/elfutils
[NixPkgs.git] / nixos / modules / misc / mandoc.nix
blob166693930b5c7c5e23098f3d31166a8838d91513
1 { config, lib, pkgs, ... }:
3 let
4   makewhatis = "${lib.getBin cfg.package}/bin/makewhatis";
6   cfg = config.documentation.man.mandoc;
8   toMandocOutput = output: (
9     lib.mapAttrsToList
10       (
11         name: value:
12           if lib.isString value || lib.isPath value then "output ${name} ${value}"
13           else if lib.isInt value then "output ${name} ${builtins.toString value}"
14           else if lib.isBool value then lib.optionalString value "output ${name}"
15           else if value == null then ""
16           else throw "Unrecognized value type ${builtins.typeOf value} of key ${name} in mandoc output settings"
17       )
18       output
19   );
21   makeLeadingSlashes = map (path: if builtins.substring 0 1 path != "/" then "/${path}" else path);
24   meta.maintainers = [ lib.maintainers.sternenseemann ];
26   options = {
27     documentation.man.mandoc = {
28       enable = lib.mkEnableOption "mandoc as the default man page viewer";
30       manPath = lib.mkOption {
31         type = with lib.types; listOf str;
32         default = [ "share/man" ];
33         example = lib.literalExpression "[ \"share/man\" \"share/man/fr\" ]";
34         apply = makeLeadingSlashes;
35         description = ''
36           Change the paths included in the MANPATH environment variable,
37           i. e. the directories where {manpage}`man(1)`
38           looks for section-specific directories of man pages.
39           You only need to change this setting if you want extra man pages
40           (e. g. in non-english languages). All values must be strings that
41           are a valid path from the target prefix (without including it).
42           The first value given takes priority. Note that this will not
43           add manpath directives to {manpage}`man.conf(5)`.
44         '';
45       };
47       cachePath = lib.mkOption {
48         type = with lib.types; listOf str;
49         default = cfg.manPath;
50         defaultText = lib.literalExpression "config.documentation.man.mandoc.manPath";
51         example = lib.literalExpression "[ \"share/man\" \"share/man/fr\" ]";
52         apply = makeLeadingSlashes;
53         description = ''
54           Change the paths where mandoc {manpage}`makewhatis(8)`generates the
55           manual page index caches. {option}`documentation.man.generateCaches`
56           should be enabled to allow cache generation. This list should only
57           include the paths to manpages installed in the system configuration,
58           i. e. /run/current-system/sw/share/man. {manpage}`makewhatis(8)`
59           creates a database in each directory using the files
60           `mansection/[arch/]title.section` and `catsection/[arch/]title.0`
61           in it. If a directory contains no manual pages, no database is
62           created in that directory.
63           This option only needs to be set manually if extra paths should be
64           indexed or {option}`documentation.man.manPath` contains paths that
65           can't be indexed.
66         '';
67       };
69       package = lib.mkOption {
70         type = lib.types.package;
71         default = pkgs.mandoc;
72         defaultText = lib.literalExpression "pkgs.mandoc";
73         description = ''
74           The `mandoc` derivation to use. Useful to override
75           configuration options used for the package.
76         '';
77       };
79       settings = lib.mkOption {
80         description = "Configuration for {manpage}`man.conf(5)`";
81         default = { };
82         type = lib.types.submodule {
83           options = {
84             manpath = lib.mkOption {
85               type = with lib.types; listOf str;
86               default = [ ];
87               example = lib.literalExpression "[ \"/run/current-system/sw/share/man\" ]";
88               description = ''
89                 Override the default search path for {manpage}`man(1)`,
90                 {manpage}`apropos(1)`, and {manpage}`makewhatis(8)`. It can be
91                 used multiple times to specify multiple paths, with the order
92                 determining the manual page search order.
93                 This is not recommended in favor of
94                 {option}`documentation.man.mandoc.manPath`, but if it's needed to
95                 specify the manpath in this way, set
96                 {option}`documentation.man.mandoc.manPath` to an empty list (`[]`).
97               '';
98             };
99             output.fragment = lib.mkOption {
100               type = lib.types.bool;
101               default = false;
102               example = true;
103               description = ''
104                 Whether to omit the <!DOCTYPE> declaration and the <html>, <head>, and <body>
105                 elements and only emit the subtree below the <body> element in HTML
106                 output of {manpage}`mandoc(1)`. The style argument will be ignored.
107                 This is useful when embedding manual content within existing documents.
108               '';
109             };
110             output.includes = lib.mkOption {
111               type = with lib.types; nullOr str;
112               default = null;
113               example = lib.literalExpression "../src/%I.html";
114               description = ''
115                 A string of relative path used as a template for the output path of
116                 linked header files (usually via the In macro) in HTML output.
117                 Instances of `%I` are replaced with the include filename. The
118                 default is not to present a hyperlink.
119               '';
120             };
121             output.indent = lib.mkOption {
122               type = with lib.types; nullOr int;
123               default = null;
124               description = ''
125                 Number of blank characters at the left margin for normal text,
126                 default of `5` for {manpage}`mdoc(7)` and `7` for
127                 {manpage}`man(7)`. Increasing this is not recommended; it may
128                 result in degraded formatting, for example overfull lines or ugly
129                 line breaks. When output is to a pager on a terminal that is less
130                 than 66 columns wide, the default is reduced to three columns.
131               '';
132             };
133             output.man = lib.mkOption {
134               type = with lib.types; nullOr str;
135               default = null;
136               example = lib.literalExpression "../html%S/%N.%S.html";
137               description = ''
138                 A template for linked manuals (usually via the Xr macro) in HTML
139                 output. Instances of ā€˜%Nā€™ and ā€˜%Sā€™ are replaced with the linked
140                 manual's name and section, respectively. If no section is included,
141                 section 1 is assumed. The default is not to present a hyperlink.
142                 If two formats are given and a file %N.%S exists in the current
143                 directory, the first format is used; otherwise, the second format is used.
144               '';
145             };
146             output.paper = lib.mkOption {
147               type = with lib.types; nullOr str;
148               default = null;
149               description = ''
150                 This option is for generating PostScript and PDF output. The paper
151                 size name may be one of `a3`, `a4`, `a5`, `legal`, or `letter`.
152                 You may also manually specify dimensions as `NNxNN`, width by
153                 height in millimetres. If an unknown value is encountered, letter
154                 is used. Output pages default to letter sized and are rendered in
155                 the Times font family, 11-point. Margins are calculated as 1/9 the
156                 page length and width. Line-height is 1.4m.
157               '';
158             };
159             output.style = lib.mkOption {
160               type = with lib.types; nullOr path;
161               default = null;
162               description = ''
163                 Path to the file used for an external style-sheet. This must be a
164                 valid absolute or relative URI.
165               '';
166             };
167             output.toc = lib.mkEnableOption ''
168               printing a table of contents near the beginning of the HTML output
169               of {manpage}`mandoc(1)` if an input file contains at least two
170               non-standard sections
171             '';
172             output.width = lib.mkOption {
173               type = with lib.types; nullOr int;
174               default = null;
175               description = ''
176                 The ASCII and UTF-8 output width, default is `78`. When output is a
177                 pager on a terminal that is less than 79 columns wide, the
178                 default is reduced to one less than the terminal width. In any case,
179                 lines that are output in literal mode are never wrapped and may
180                 exceed the output width.
181               '';
182             };
183           };
184         };
185       };
187       extraConfig = lib.mkOption {
188         type = lib.types.lines;
189         default = "";
190         description = ''
191           Extra configuration to write to {manpage}`man.conf(5)`.
192         '';
193       };
194     };
195   };
197   config = lib.mkIf cfg.enable {
198     environment = {
199       systemPackages = [ cfg.package ];
201       etc."man.conf".text = lib.concatStringsSep "\n" (
202         (map (path: "manpath ${path}") cfg.settings.manpath)
203         ++ (toMandocOutput cfg.settings.output)
204         ++ [ cfg.extraConfig ]
205       );
207       # create mandoc.db for whatis(1), apropos(1) and man(1) -k
208       # TODO(@sternenseemman): fix symlinked directories not getting indexed,
209       # see: https://inbox.vuxu.org/mandoc-tech/20210906171231.GF83680@athene.usta.de/T/#e85f773c1781e3fef85562b2794f9cad7b2909a3c
210       extraSetup = lib.mkIf config.documentation.man.generateCaches ''
211         for man_path in ${lib.concatMapStringsSep " " (path: "$out" + lib.escapeShellArg path) cfg.cachePath}
212         do
213           [[ -d "$man_path" ]] && ${makewhatis} -T utf8 $man_path
214         done
215       '';
217       # tell mandoc the paths containing man pages
218       profileRelativeSessionVariables."MANPATH" = lib.mkIf (cfg.manPath != [ ]) cfg.manPath;
219     };
220   };