aboutsummaryrefslogtreecommitdiff
path: root/doc/manual/utils.nix
blob: f78e6bb02b2edb88b7a037b12f9fcc10b73c26b7 (plain)
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
with builtins;

rec {
  splitLines = s: filter (x: !isList x) (split "\n" s);

  concatStrings = concatStringsSep "";

  replaceStringsRec = from: to: string:
    # recursively replace occurrences of `from` with `to` within `string`
    # example:
    #     replaceStringRec "--" "-" "hello-----world"
    #     => "hello-world"
    let
      replaced = replaceStrings [ from ] [ to ] string;
    in
      if replaced == string then string else replaceStringsRec from to replaced;

  squash = replaceStringsRec "\n\n\n" "\n\n";

  trim = string:
    # trim trailing spaces and squash non-leading spaces
    let
      trimLine = line:
        let
          # separate leading spaces from the rest
          parts = split "(^ *)" line;
          spaces = head (elemAt parts 1);
          rest = elemAt parts 2;
          # drop trailing spaces
          body = head (split " *$" rest);
        in spaces + replaceStringsRec "  " " " body;
    in concatStringsSep "\n" (map trimLine (splitLines string));

  # FIXME: O(n^2)
  unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [];

  nameValuePair = name: value: { inherit name value; };

  filterAttrs = pred: set:
    listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));

  showSetting = { useAnchors }: name: { description, documentDefault, defaultValue, aliases, value }:
    let
      result = squash ''
          - ${if useAnchors
              then ''<span id="conf-${name}">[`${name}`](#conf-${name})</span>''
              else ''`${name}`''}

          ${indent "  " body}
        '';

      # separate body to cleanly handle indentation
      body = ''
          ${description}

          **Default:** ${showDefault documentDefault defaultValue}

          ${showAliases aliases}
        '';

      showDefault = documentDefault: defaultValue:
        if documentDefault then
          # a StringMap value type is specified as a string, but
          # this shows the value type. The empty stringmap is `null` in
          # JSON, but that converts to `{ }` here.
          if defaultValue == "" || defaultValue == [] || isAttrs defaultValue
            then "*empty*"
            else if isBool defaultValue then
              if defaultValue then "`true`" else "`false`"
            else "`${toString defaultValue}`"
        else "*machine-specific*";

      showAliases = aliases:
          if aliases == [] then "" else
            "**Deprecated alias:** ${(concatStringsSep ", " (map (s: "`${s}`") aliases))}";

    in result;

  indent = prefix: s:
    concatStringsSep "\n" (map (x: if x == "" then x else "${prefix}${x}") (splitLines s));

  showSettings = args: settingsInfo: concatStrings (attrValues (mapAttrs (showSetting args) settingsInfo));
}