├── .envrc ├── .github ├── dependabot.yml ├── release.yml └── workflows │ └── build.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── default.nix ├── doc └── migration.md ├── flake.lock ├── flake.nix ├── src ├── comment.rs ├── commonmark.rs ├── format.rs ├── legacy.rs ├── main.rs ├── snapshots │ ├── nixdoc__test__arg_formatting.snap │ ├── nixdoc__test__commonmark.snap │ ├── nixdoc__test__description_of_lib_debug.snap │ ├── nixdoc__test__doc_comment.snap │ ├── nixdoc__test__doc_comment_no_duplicate_arguments.snap │ ├── nixdoc__test__doc_comment_section_description.snap │ ├── nixdoc__test__headings.snap │ ├── nixdoc__test__inherited_exports.snap │ ├── nixdoc__test__json_output.snap │ ├── nixdoc__test__line_comments.snap │ ├── nixdoc__test__main.snap │ ├── nixdoc__test__main_minimal.snap │ ├── nixdoc__test__multi_line.snap │ └── nixdoc__test__patterns.snap └── test.rs └── test ├── arg-formatting.nix ├── commonmark.md ├── doc-comment-arguments.nix ├── doc-comment-sec-heading.nix ├── doc-comment.nix ├── headings.md ├── inherited-exports.nix ├── lib-debug.nix ├── line-comments.nix ├── multi-line.nix ├── patterns.nix ├── strings.json └── strings.nix /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "cargo" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | ignore: 12 | - dependency-name: "*" 13 | update-types: ["version-update:semver-patch"] 14 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | authors: 4 | - dependabot 5 | labels: 6 | - chore 7 | categories: 8 | - title: What's Changed 9 | labels: 10 | - "*" 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | build: 14 | strategy: 15 | matrix: 16 | os: [ ubuntu-latest, macos-latest ] 17 | fail-fast: false 18 | runs-on: ${{ matrix.os }} 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: cachix/install-nix-action@v30 22 | - name: Add nix-community cache 23 | uses: cachix/cachix-action@v15 24 | with: 25 | name: nix-community 26 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 27 | - run: nix flake check 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | .direnv 5 | result* 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: nix 2 | sudo: true 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Upcoming release 4 | 5 | ## Version 3.1.0 6 | 7 | Add `--anchor-prefix` to remove or customize the `function-library-` prefix. 8 | 9 | A header won't be rendered when `--description` and `--category` are empty. 10 | This makes the generated markdown more flexible for inclusion in other documents. 11 | 12 | ## Version 3.0.8 13 | 14 | Add `--json-output`, providing a JSON representation of the documentation. 15 | 16 | Fix: attrsets in patterns are now skipped correctly. 17 | 18 | ## Version 3.0.7 19 | 20 | Add support for empty prefix flags. 21 | Allows for improved generic usage in nixpkgs/lib and other projects. 22 | 23 | Empty prefix is now possible. 24 | Issue: https://github.com/nix-community/nixdoc/issues/119 by @roberth 25 | 26 | by @hsjobeki; 27 | 28 | in https://github.com/nix-community/nixdoc/pull/122. 29 | 30 | ## Version 3.0.6 31 | 32 | Exposes the package recipe under `recipes.default` so it can easily be re-used. 33 | Example: 34 | 35 | ``` 36 | nix-repl> :l https://github.com/nixos/nixpkgs/tarball/nixpkgs-unstable 37 | nix-repl> :l https://github.com/nix-community/nixdoc/tarball/master 38 | nix-repl> pkgs.callPackage recipes.default {} 39 | ``` 40 | 41 | ## Version 3.0.5 42 | 43 | Fixes: incompatibility with nixpkgs in 3.0.3 and 3.0.4 44 | 45 | by @hsjobeki; 46 | 47 | in https://github.com/nix-community/nixdoc/pull/121. 48 | 49 | ## Version 3.0.4 50 | 51 | Fixes: issue with headings ids introduced with 3.0.3 52 | 53 | by @hsjobeki; 54 | 55 | in https://github.com/nix-community/nixdoc/pull/117. 56 | 57 | ## Version 3.0.3 58 | 59 | Fixes: shifting issue with commonmark headings https://github.com/nix-community/nixdoc/issues/113 60 | 61 | by @hsjobeki; 62 | 63 | in https://github.com/nix-community/nixdoc/pull/115. 64 | 65 | ## Version 3.0.2 66 | 67 | Avoid displaying arguments when a doc-comment is already in place. 68 | 69 | by @hsjobeki; 70 | 71 | in https://github.com/nix-community/nixdoc/pull/109. 72 | 73 | ## Version 3.0.1 74 | 75 | ### New Features 76 | 77 | - **Official Doc-Comments Support:** We've introduced support for official doc-comments as defined in [RFC145](https://github.com/NixOS/rfcs/pull/145). This enhancement aligns nixdoc with our latest documentation standard. 78 | 79 | ### Deprecated Features 80 | 81 | - **Legacy Custom Format:** The custom nixdoc format is now considered a legacy feature. We plan to phase it out in future versions to streamline documentation practices. 82 | - We encourage users to transition to the official doc-comment format introduced in this release. 83 | - For now we will continue to maintain the legacy format, but will not accept new features or enhancements for it. This decision allows for a period of transition to the new documentation practices. 84 | 85 | See [Migration guide](./doc/migration.md) for smooth transition 86 | 87 | by @hsjobeki; co-authored by @mightyiam 88 | 89 | in https://github.com/nix-community/nixdoc/pull/91. 90 | 91 | ## Version 3.0.0 92 | 93 | Removed due to invalid lock file. 94 | 95 | ## 2.7.0 96 | 97 | - Added support to customise the attribute set prefix, which was previously hardcoded to `lib`. 98 | The default is still `lib`, but you can pass `--prefix` now to use something else like `utils`. 99 | 100 | By @Janik-Haag in https://github.com/nix-community/nixdoc/pull/97 101 | 102 | ## 2.6.0 103 | 104 | - After doing a great job of maintaining the project for this year, @asymmetric is passing on the torch to @infinisil! 105 | - Multi-line comments at the top of the file now become the section description text. 106 | By @phaer in https://github.com/nix-community/nixdoc/pull/70 107 | 108 | For example, the following file 109 | ```nix 110 | /* 111 | This is just a test! 112 | */ 113 | { 114 | /* Increments a number by one */ 115 | increment = x: x + 1; 116 | } 117 | ``` 118 | 119 | turns into the following markdown: 120 | 121 | ```markdown 122 | # Test {#sec-functions-library-test} 123 | This is just a test! 124 | 125 | ## `lib.test.increment` {#function-library-lib.test.increment} 126 | 127 | Increments a number by one 128 | 129 | `x` 130 | 131 | : Function argument 132 | ``` 133 | 134 | whereas before, the top section would've been empty. 135 | 136 | ## 2.5.1 137 | 138 | - readme: fix link to rendering example by @infinisil in https://github.com/nix-community/nixdoc/pull/67 139 | - Fix indentation of structured multi-line comments by @asymmetric in https://github.com/nix-community/nixdoc/pull/81 140 | 141 | ## 2.5.0 142 | 143 | ## 2.4.0 144 | 145 | - Fix line indentation stripping by @infinisil in https://github.com/nix-community/nixdoc/pull/62 146 | 147 | ## 2.3.0 148 | 149 | - nix: remove outdated outputHashes by @asymmetric in https://github.com/nix-community/nixdoc/pull/38 150 | - add snapshot testing by @asymmetric in https://github.com/nix-community/nixdoc/pull/39 151 | - Create dependabot.yml by @asymmetric in https://github.com/nix-community/nixdoc/pull/41 152 | - chore(deps): bump cachix/install-nix-action from 20 to 22 by @dependabot in https://github.com/nix-community/nixdoc/pull/42 153 | - complete the markdown transition by @pennae in https://github.com/nix-community/nixdoc/pull/40 154 | 155 | ## 2.2.0 156 | 157 | - Update rnix to 0.11 by @pennae [#36](https://github.com/nix-community/nixdoc/pull/36) 158 | 159 | ## 2.1.0 160 | 161 | - Correctly support nested identifiers by @infinisil [#27](https://github.com/nix-community/nixdoc/pull/27) 162 | 163 | ## 2.0.0 164 | 165 | - Switched output format from DocBook to CommonMark by @ryantm [#25](https://github.com/nix-community/nixdoc/pull/25) 166 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | A SERMON ON ETHICS AND LOVE 2 | =========================== 3 | 4 | One day Mal-2 asked the messenger spirit Saint Gulik to approach the 5 | Goddess and request Her presence for some desperate advice. Shortly 6 | afterwards the radio came on by itself, and an ethereal female Voice 7 | said **YES?** 8 | 9 | "O! Eris! Blessed Mother of Man! Queen of Chaos! Daughter of Discord! 10 | Concubine of Confusion! O! Exquisite Lady, I beseech You to lift a 11 | heavy burden from my heart!" 12 | 13 | **WHAT BOTHERS YOU, MAL? YOU DON'T SOUND WELL.** 14 | 15 | "I am filled with fear and tormented with terrible visions of pain. 16 | Everywhere people are hurting one another, the planet is rampant with 17 | injustices, whole societies plunder groups of their own people, 18 | mothers imprison sons, children perish while brothers war. O, woe." 19 | 20 | **WHAT IS THE MATTER WITH THAT, IF IT IS WHAT YOU WANT TO DO?** 21 | 22 | "But nobody Wants it! Everybody hates it." 23 | 24 | **OH. WELL, THEN *STOP*.** 25 | 26 | At which moment She turned herself into an aspirin commercial and left 27 | The Polyfather stranded alone with his species. 28 | 29 | SINISTER DEXTER HAS A BROKEN SPIROMETER. 30 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anstream" 7 | version = "0.6.13" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" 10 | dependencies = [ 11 | "anstyle", 12 | "anstyle-parse", 13 | "anstyle-query", 14 | "anstyle-wincon", 15 | "colorchoice", 16 | "utf8parse", 17 | ] 18 | 19 | [[package]] 20 | name = "anstyle" 21 | version = "1.0.6" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" 24 | 25 | [[package]] 26 | name = "anstyle-parse" 27 | version = "0.2.3" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 30 | dependencies = [ 31 | "utf8parse", 32 | ] 33 | 34 | [[package]] 35 | name = "anstyle-query" 36 | version = "1.0.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 39 | dependencies = [ 40 | "windows-sys", 41 | ] 42 | 43 | [[package]] 44 | name = "anstyle-wincon" 45 | version = "3.0.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 48 | dependencies = [ 49 | "anstyle", 50 | "windows-sys", 51 | ] 52 | 53 | [[package]] 54 | name = "autocfg" 55 | version = "1.1.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 58 | 59 | [[package]] 60 | name = "clap" 61 | version = "4.5.2" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" 64 | dependencies = [ 65 | "clap_builder", 66 | "clap_derive", 67 | ] 68 | 69 | [[package]] 70 | name = "clap_builder" 71 | version = "4.5.2" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 74 | dependencies = [ 75 | "anstream", 76 | "anstyle", 77 | "clap_lex", 78 | "strsim", 79 | ] 80 | 81 | [[package]] 82 | name = "clap_derive" 83 | version = "4.5.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" 86 | dependencies = [ 87 | "heck", 88 | "proc-macro2", 89 | "quote", 90 | "syn", 91 | ] 92 | 93 | [[package]] 94 | name = "clap_lex" 95 | version = "0.7.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 98 | 99 | [[package]] 100 | name = "colorchoice" 101 | version = "1.0.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 104 | 105 | [[package]] 106 | name = "console" 107 | version = "0.15.8" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 110 | dependencies = [ 111 | "encode_unicode", 112 | "lazy_static", 113 | "libc", 114 | "windows-sys", 115 | ] 116 | 117 | [[package]] 118 | name = "countme" 119 | version = "3.0.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" 122 | 123 | [[package]] 124 | name = "encode_unicode" 125 | version = "0.3.6" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 128 | 129 | [[package]] 130 | name = "hashbrown" 131 | version = "0.14.3" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 134 | 135 | [[package]] 136 | name = "heck" 137 | version = "0.4.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 140 | 141 | [[package]] 142 | name = "insta" 143 | version = "1.42.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" 146 | dependencies = [ 147 | "console", 148 | "linked-hash-map", 149 | "once_cell", 150 | "similar", 151 | ] 152 | 153 | [[package]] 154 | name = "itoa" 155 | version = "1.0.10" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 158 | 159 | [[package]] 160 | name = "lazy_static" 161 | version = "1.4.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 164 | 165 | [[package]] 166 | name = "libc" 167 | version = "0.2.153" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 170 | 171 | [[package]] 172 | name = "linked-hash-map" 173 | version = "0.5.6" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 176 | 177 | [[package]] 178 | name = "memoffset" 179 | version = "0.9.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 182 | dependencies = [ 183 | "autocfg", 184 | ] 185 | 186 | [[package]] 187 | name = "nixdoc" 188 | version = "3.0.4" 189 | dependencies = [ 190 | "clap", 191 | "insta", 192 | "rnix", 193 | "rowan", 194 | "serde", 195 | "serde_json", 196 | "textwrap", 197 | ] 198 | 199 | [[package]] 200 | name = "once_cell" 201 | version = "1.20.2" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 204 | 205 | [[package]] 206 | name = "proc-macro2" 207 | version = "1.0.78" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" 210 | dependencies = [ 211 | "unicode-ident", 212 | ] 213 | 214 | [[package]] 215 | name = "quote" 216 | version = "1.0.35" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 219 | dependencies = [ 220 | "proc-macro2", 221 | ] 222 | 223 | [[package]] 224 | name = "rnix" 225 | version = "0.12.0" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "6f15e00b0ab43abd70d50b6f8cd021290028f9b7fdd7cdfa6c35997173bc1ba9" 228 | dependencies = [ 229 | "rowan", 230 | ] 231 | 232 | [[package]] 233 | name = "rowan" 234 | version = "0.15.15" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49" 237 | dependencies = [ 238 | "countme", 239 | "hashbrown", 240 | "memoffset", 241 | "rustc-hash", 242 | "text-size", 243 | ] 244 | 245 | [[package]] 246 | name = "rustc-hash" 247 | version = "1.1.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 250 | 251 | [[package]] 252 | name = "ryu" 253 | version = "1.0.17" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 256 | 257 | [[package]] 258 | name = "serde" 259 | version = "1.0.197" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 262 | dependencies = [ 263 | "serde_derive", 264 | ] 265 | 266 | [[package]] 267 | name = "serde_derive" 268 | version = "1.0.197" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 271 | dependencies = [ 272 | "proc-macro2", 273 | "quote", 274 | "syn", 275 | ] 276 | 277 | [[package]] 278 | name = "serde_json" 279 | version = "1.0.114" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" 282 | dependencies = [ 283 | "itoa", 284 | "ryu", 285 | "serde", 286 | ] 287 | 288 | [[package]] 289 | name = "similar" 290 | version = "2.4.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" 293 | 294 | [[package]] 295 | name = "smawk" 296 | version = "0.3.2" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 299 | 300 | [[package]] 301 | name = "strsim" 302 | version = "0.11.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" 305 | 306 | [[package]] 307 | name = "syn" 308 | version = "2.0.52" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" 311 | dependencies = [ 312 | "proc-macro2", 313 | "quote", 314 | "unicode-ident", 315 | ] 316 | 317 | [[package]] 318 | name = "text-size" 319 | version = "1.1.1" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" 322 | 323 | [[package]] 324 | name = "textwrap" 325 | version = "0.16.1" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" 328 | dependencies = [ 329 | "smawk", 330 | "unicode-linebreak", 331 | "unicode-width", 332 | ] 333 | 334 | [[package]] 335 | name = "unicode-ident" 336 | version = "1.0.12" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 339 | 340 | [[package]] 341 | name = "unicode-linebreak" 342 | version = "0.1.5" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 345 | 346 | [[package]] 347 | name = "unicode-width" 348 | version = "0.1.11" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 351 | 352 | [[package]] 353 | name = "utf8parse" 354 | version = "0.2.1" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 357 | 358 | [[package]] 359 | name = "windows-sys" 360 | version = "0.52.0" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 363 | dependencies = [ 364 | "windows-targets", 365 | ] 366 | 367 | [[package]] 368 | name = "windows-targets" 369 | version = "0.52.4" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 372 | dependencies = [ 373 | "windows_aarch64_gnullvm", 374 | "windows_aarch64_msvc", 375 | "windows_i686_gnu", 376 | "windows_i686_msvc", 377 | "windows_x86_64_gnu", 378 | "windows_x86_64_gnullvm", 379 | "windows_x86_64_msvc", 380 | ] 381 | 382 | [[package]] 383 | name = "windows_aarch64_gnullvm" 384 | version = "0.52.4" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 387 | 388 | [[package]] 389 | name = "windows_aarch64_msvc" 390 | version = "0.52.4" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 393 | 394 | [[package]] 395 | name = "windows_i686_gnu" 396 | version = "0.52.4" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 399 | 400 | [[package]] 401 | name = "windows_i686_msvc" 402 | version = "0.52.4" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 405 | 406 | [[package]] 407 | name = "windows_x86_64_gnu" 408 | version = "0.52.4" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 411 | 412 | [[package]] 413 | name = "windows_x86_64_gnullvm" 414 | version = "0.52.4" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 417 | 418 | [[package]] 419 | name = "windows_x86_64_msvc" 420 | version = "0.52.4" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 423 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nixdoc" 3 | version = "3.0.4" 4 | authors = ["Vincent Ambo ", "asymmetric"] 5 | edition = "2021" 6 | description = "Generate CommonMark from Nix library functions" 7 | 8 | [dependencies] 9 | rnix = "0.12" 10 | rowan = "0.15.11" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | textwrap = "0.16" 14 | clap = { version = "4.4.4", features = ["derive"] } 15 | 16 | [dev-dependencies] 17 | insta = "1.42.0" 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nixdoc 2 | 3 | This tool is used to generate reference documentation for Nix library functions defined in [Nixpkgs' `lib`](https://github.com/NixOS/nixpkgs/tree/master/lib). 4 | 5 | Check out [this example](https://nixos.org/manual/nixpkgs/unstable/#sec-functions-library-strings) of documentation generated for the [`lib/strings.nix`](https://github.com/NixOS/nixpkgs/blob/nixpkgs-unstable/lib/strings.nix) file. 6 | 7 | It uses [rnix](https://github.com/nix-community/rnix-parser) to parse Nix source files, 8 | which are then transformed into a CommonMark (with some syntax extensions) representation of the 9 | function set. 10 | 11 | ## Comment format 12 | 13 | This tool implements a subset of the doc-comment standard specified in [RFC-145/doc-comments](https://github.com/NixOS/rfcs/blob/master/rfcs/0145-doc-strings.md). 14 | But, it is currently limited to generating documentation for statically analysable attribute paths only. 15 | In the future, it could be the role of a Nix interpreter to obtain the values to be documented and their doc-comments. 16 | 17 | It is important to start doc-comments with the additional asterisk (`*`) -> `/**` which renders as a doc-comment. 18 | 19 | The content of the doc-comment should conform to the [Commonmark](https://spec.commonmark.org/0.30/) specification. 20 | 21 | ### Example 22 | 23 | The following is an example of markdown documentation for new and current users of nixdoc. 24 | 25 | > Sidenote: Indentation is automatically detected and should be consistent across the content. 26 | > 27 | > If you are used to multiline-strings (`''`) in nix this should be intuitive to follow. 28 | 29 | ````nix 30 | { 31 | /** 32 | This function adds two numbers 33 | 34 | # Example 35 | 36 | ```nix 37 | add 4 5 38 | => 39 | 9 40 | ``` 41 | 42 | # Type 43 | 44 | ``` 45 | add :: Number -> Number -> Number 46 | ``` 47 | 48 | # Arguments 49 | 50 | a 51 | : The first number 52 | 53 | b 54 | : The second number 55 | 56 | */ 57 | add = a: b: a + b; 58 | } 59 | ```` 60 | 61 | > Note: Within nixpkgs the convention of using [definition-lists](https://www.markdownguide.org/extended-syntax/#definition-lists) for documenting arguments has been established. 62 | 63 | ## Usage 64 | 65 | Refer to `nixdoc --help` for the most up-to-date usage information. 66 | 67 | For a minimal format, suitable for inclusion into a dedicated documentation page, use: 68 | 69 | ```sh 70 | nixdoc --file lib.nix --category "" --description "" --prefix "" --anchor-prefix "" >lib.md 71 | ``` 72 | 73 | ## Custom nixdoc format (Legacy) 74 | 75 | You should consider migrating to the newer format described above. 76 | 77 | See [Migration guide](./doc/migration.md). 78 | 79 | ### Comment format (legacy) 80 | 81 | Identifiers are included in the documentation if they have 82 | a preceding comment in multiline syntax `/* something */`. You should consider migrating to the new format described above. 83 | 84 | Two special line beginnings are recognized: 85 | 86 | * `Example:` Everything following this line will be assumed to be a 87 | verbatim usage example. 88 | * `Type:` This line will be interpreted as a faux-type signature. 89 | 90 | These will result in appropriate elements being inserted into the 91 | output. 92 | 93 | ### Function arguments (legacy) 94 | 95 | Function arguments can be documented by prefixing them with a comment: 96 | 97 | ``` 98 | /* This function does the thing a number of times. */ 99 | myFunction = 100 | # The thing to do 101 | thing: 102 | # How many times to do it 103 | n: doNTimes n thing 104 | ``` 105 | 106 | ## Caveats & TODOs 107 | 108 | Please check the [issues](https://github.com/nix-community/nixdoc/issues) page. 109 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import 2 | ( 3 | let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in 4 | fetchTarball { 5 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 6 | sha256 = lock.nodes.flake-compat.locked.narHash; 7 | } 8 | ) 9 | { src = ./.; } 10 | ).defaultNix 11 | -------------------------------------------------------------------------------- /doc/migration.md: -------------------------------------------------------------------------------- 1 | # Migration Guide 2 | 3 | Upgrading from nixdoc <= 2.x.x to >= 3.0.0 4 | 5 | To leverage the new doc-comment features and prepare for the deprecation of the legacy format, follow these guidelines: 6 | 7 | ## Documentation Comments 8 | 9 | - Use double asterisks `/** */` to mark comments intended as documentation. This differentiates them from internal comments and ensures they are properly processed as part of the documentation. 10 | 11 | **Example:** 12 | 13 | `lib/attrsets.nix (old format)` 14 | ````nix 15 | /* Filter an attribute set by removing all attributes for which the 16 | given predicate return false. 17 | Example: 18 | filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; } 19 | => { foo = 1; } 20 | Type: 21 | filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet 22 | */ 23 | filterAttrs = 24 | # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute or `false` to exclude the attribute. 25 | pred: 26 | # The attribute set to filter 27 | set: 28 | listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set)); 29 | ```` 30 | 31 | -> 32 | 33 | `lib/attrsets.nix (new format)` 34 | ````nix 35 | /** 36 | Filter an attribute set by removing all attributes for which the 37 | given predicate return false. 38 | 39 | # Example 40 | 41 | ```nix 42 | filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; } 43 | => { foo = 1; } 44 | ``` 45 | 46 | # Type 47 | 48 | ``` 49 | filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet 50 | ``` 51 | 52 | # Arguments 53 | 54 | **pred** 55 | : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute. 56 | 57 | **set** 58 | : The attribute set to filter 59 | */ 60 | filterAttrs = 61 | pred: 62 | set: 63 | listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set)); 64 | ```` 65 | 66 | ## Documenting Arguments 67 | 68 | With the introduction of RFC145, there is a shift in how arguments are documented. While direct "argument" documentation is not specified, you can still document arguments effectively within your doc-comments by writing explicit markdown. 69 | 70 | **Example:** Migrating **Single Argument Documentation** 71 | 72 | The approach to documenting single arguments has evolved. Instead of individual argument comments, document the function and its arguments together. 73 | 74 | > Note: Within nixpkgs the convention of using [definition-lists](https://www.markdownguide.org/extended-syntax/#definition-lists) for documenting arguments has been established. 75 | 76 | ```nix 77 | { 78 | /** 79 | The `id` function returns the provided value unchanged. 80 | 81 | # Arguments 82 | 83 | `x` (Any) 84 | : The value to be returned. 85 | 86 | */ 87 | id = x: x; 88 | } 89 | ``` 90 | 91 | If arguments require more complex documentation consider starting an extra section per argument 92 | 93 | ```nix 94 | { 95 | /** 96 | The `id` function returns the provided value unchanged. 97 | 98 | # Arguments 99 | 100 | ## **x** (Any) 101 | (...Some comprehensive documentation) 102 | 103 | */ 104 | id = x: x; 105 | } 106 | ``` 107 | 108 | **Example:** Documenting Structured Arguments 109 | Structured arguments can be documented (described in RFC145 as 'lambda formals'), using doc-comments. 110 | 111 | ```nix 112 | { 113 | /** 114 | The `add` function calculates the sum of `a` and `b`. 115 | */ 116 | add = { 117 | /** The first number to add. */ 118 | a, 119 | /** The second number to add. */ 120 | b 121 | }: a + b; 122 | } 123 | ``` 124 | 125 | Ensure your documentation comments start with double asterisks to comply with the new standard. The legacy format remains supported for now but will not receive new features. It will be removed once important downstream projects have been migrated. 126 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-compat": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1732722421, 7 | "narHash": "sha256-HRJ/18p+WoXpWJkcdsk9St5ZiukCqSDgbOGFa8Okehg=", 8 | "owner": "edolstra", 9 | "repo": "flake-compat", 10 | "rev": "9ed2ac151eada2306ca8c418ebd97807bb08f6ac", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "edolstra", 15 | "repo": "flake-compat", 16 | "type": "github" 17 | } 18 | }, 19 | "flake-utils": { 20 | "inputs": { 21 | "systems": "systems" 22 | }, 23 | "locked": { 24 | "lastModified": 1731533236, 25 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 26 | "owner": "numtide", 27 | "repo": "flake-utils", 28 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 29 | "type": "github" 30 | }, 31 | "original": { 32 | "owner": "numtide", 33 | "repo": "flake-utils", 34 | "type": "github" 35 | } 36 | }, 37 | "nixpkgs": { 38 | "locked": { 39 | "lastModified": 1733024928, 40 | "narHash": "sha256-n/DOfpKH1vkukuBnach91QBQId2dr5tkE7/7UrkV2zw=", 41 | "owner": "NixOS", 42 | "repo": "nixpkgs", 43 | "rev": "2c27ab2e60502d1ebb7cf38909de38663f762a79", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "NixOS", 48 | "ref": "nixpkgs-unstable", 49 | "repo": "nixpkgs", 50 | "type": "github" 51 | } 52 | }, 53 | "root": { 54 | "inputs": { 55 | "flake-compat": "flake-compat", 56 | "flake-utils": "flake-utils", 57 | "nixpkgs": "nixpkgs" 58 | } 59 | }, 60 | "systems": { 61 | "locked": { 62 | "lastModified": 1681028828, 63 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 64 | "owner": "nix-systems", 65 | "repo": "default", 66 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 67 | "type": "github" 68 | }, 69 | "original": { 70 | "owner": "nix-systems", 71 | "repo": "default", 72 | "type": "github" 73 | } 74 | } 75 | }, 76 | "root": "root", 77 | "version": 7 78 | } 79 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "nixdoc"; 3 | 4 | inputs = { 5 | flake-compat = { 6 | url = "github:edolstra/flake-compat"; 7 | flake = false; 8 | }; 9 | flake-utils.url = "github:numtide/flake-utils"; 10 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 11 | }; 12 | outputs = { self, nixpkgs, flake-utils, ... }: 13 | let 14 | recipe = { lib, rustPlatform }: 15 | let 16 | package = (lib.importTOML ./Cargo.toml).package; 17 | in 18 | rustPlatform.buildRustPackage { 19 | pname = package.name; 20 | version = package.version; 21 | src = ./.; 22 | cargoLock.lockFile = ./Cargo.lock; 23 | }; 24 | in 25 | { 26 | recipes.default = recipe; 27 | } 28 | // 29 | flake-utils.lib.eachDefaultSystem (system: 30 | let 31 | nixpkgsDocs = import "${nixpkgs}/doc" { 32 | pkgs = import nixpkgs { 33 | inherit system; 34 | overlays = [ 35 | (_: _: { nixdoc = self.packages.${system}.default; } ) 36 | ]; 37 | }; 38 | }; 39 | pkgs = nixpkgs.legacyPackages.${system}; 40 | in 41 | { 42 | packages.default = pkgs.callPackage recipe { }; 43 | apps.default = flake-utils.lib.mkApp { 44 | drv = self.packages.${system}.default; 45 | name = self.packages.${system}.default.pname; 46 | }; 47 | 48 | checks = { 49 | inherit nixpkgsDocs; 50 | test = self.packages.${system}.default.overrideAttrs (drvAttrs: { 51 | postCheck = drvAttrs.postCheck or "" + '' 52 | ${pkgs.rustfmt}/bin/rustfmt --check src/**.rs 53 | ${pkgs.clippy}/bin/cargo-clippy --no-deps -- -D warnings 54 | ''; 55 | }); 56 | }; 57 | 58 | devShells.default = pkgs.mkShell { 59 | buildInputs = with pkgs; [ 60 | cargo 61 | cargo-insta 62 | clippy 63 | rustfmt 64 | rustc 65 | ]; 66 | }; 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /src/comment.rs: -------------------------------------------------------------------------------- 1 | use rnix::ast::{self, AstToken}; 2 | use rnix::{match_ast, SyntaxNode}; 3 | use rowan::ast::AstNode; 4 | 5 | /// Implements functions for doc-comments according to rfc145. 6 | pub trait DocComment { 7 | fn doc_text(&self) -> Option<&str>; 8 | } 9 | 10 | impl DocComment for ast::Comment { 11 | /// Function returns the contents of the doc-comment, if the [ast::Comment] is a 12 | /// doc-comment, or None otherwise. 13 | /// 14 | /// Note: [ast::Comment] holds both the single-line and multiline comment. 15 | /// 16 | /// /**{content}*/ 17 | /// -> {content} 18 | /// 19 | /// It is named `doc_text` to complement [ast::Comment::text]. 20 | fn doc_text(&self) -> Option<&str> { 21 | let text = self.syntax().text(); 22 | // Check whether this is a doc-comment 23 | if text.starts_with(r#"/**"#) && self.text().starts_with('*') { 24 | self.text().strip_prefix('*') 25 | } else { 26 | None 27 | } 28 | } 29 | } 30 | 31 | /// Function retrieves a doc-comment from the [ast::Expr] 32 | /// 33 | /// Returns an [Option] of the first suitable doc-comment. 34 | /// Returns [None] in case no suitable comment was found. 35 | /// 36 | /// Doc-comments can appear in two places for any expression 37 | /// 38 | /// ```nix 39 | /// # (1) directly before the expression (anonymous) 40 | /// /** Doc */ 41 | /// bar: bar; 42 | /// 43 | /// # (2) when assigning a name. 44 | /// { 45 | /// /** Doc */ 46 | /// foo = bar: bar; 47 | /// } 48 | /// ``` 49 | /// 50 | /// If the doc-comment is not found in place (1) the search continues at place (2) 51 | /// More precisely before the NODE_ATTRPATH_VALUE (ast) 52 | /// If no doc-comment was found in place (1) or (2) this function returns None. 53 | pub fn get_expr_docs(expr: &SyntaxNode) -> Option { 54 | if let Some(doc) = get_doc_comment(expr) { 55 | // Found in place (1) 56 | doc.doc_text().map(|v| v.to_owned()) 57 | } else if let Some(ref parent) = expr.parent() { 58 | match_ast! { 59 | match parent { 60 | ast::AttrpathValue(_) => { 61 | if let Some(doc_comment) = get_doc_comment(parent) { 62 | doc_comment.doc_text().map(|v| v.to_owned()) 63 | }else{ 64 | None 65 | } 66 | }, 67 | _ => { 68 | // Yet unhandled ast-nodes 69 | None 70 | } 71 | 72 | } 73 | } 74 | // None 75 | } else { 76 | // There is no parent; 77 | // No further places where a doc-comment could be. 78 | None 79 | } 80 | } 81 | 82 | /// Looks backwards from the given expression 83 | /// Only whitespace or non-doc-comments are allowed in between an expression and the doc-comment. 84 | /// Any other Node or Token stops the peek. 85 | fn get_doc_comment(expr: &SyntaxNode) -> Option { 86 | let mut prev = expr.prev_sibling_or_token(); 87 | loop { 88 | match prev { 89 | Some(rnix::NodeOrToken::Token(ref token)) => { 90 | match_ast! { match token { 91 | ast::Whitespace(_) => { 92 | prev = token.prev_sibling_or_token(); 93 | }, 94 | ast::Comment(it) => { 95 | if it.doc_text().is_some() { 96 | break Some(it); 97 | }else{ 98 | //Ignore non-doc comments. 99 | prev = token.prev_sibling_or_token(); 100 | } 101 | }, 102 | _ => { 103 | break None; 104 | } 105 | }} 106 | } 107 | _ => break None, 108 | }; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/commonmark.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Vincent Ambo 2 | // 3 | // nixdoc is free software: you can redistribute it and/or modify it 4 | // under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! This module implements CommonMark output for a struct 17 | //! representing a single entry in the manual. 18 | 19 | use serde::Serialize; 20 | 21 | /// Represent a single function argument name and its (optional) 22 | /// doc-string. 23 | #[derive(Clone, Debug, Serialize)] 24 | pub struct SingleArg { 25 | pub name: String, 26 | pub doc: Option, 27 | } 28 | 29 | /// Represent a function argument, which is either a flat identifier 30 | /// or a pattern set. 31 | #[derive(Clone, Debug, Serialize)] 32 | pub enum Argument { 33 | /// Flat function argument (e.g. `n: n * 2`). 34 | Flat(SingleArg), 35 | 36 | /// Pattern function argument (e.g. `{ name, age }: ...`) 37 | Pattern(Vec), 38 | } 39 | 40 | impl Argument { 41 | /// Write CommonMark structure for a single function argument. 42 | /// We use the definition list extension, which prepends each argument with `: `. 43 | /// For pattern arguments, we create a nested definition list. 44 | fn format_argument(self) -> String { 45 | match self { 46 | // Write a flat argument entry, e.g. `id = x: x` 47 | // 48 | // `x` 49 | // : Function argument 50 | Argument::Flat(arg) => { 51 | format!( 52 | "`{}`\n\n: {}\n\n", 53 | arg.name, 54 | handle_indentation(arg.doc.unwrap_or("Function argument".into()).trim()) 55 | ) 56 | } 57 | 58 | // Write a pattern argument entry and its individual 59 | // parameters as a nested structure, e.g.: 60 | // 61 | // `foo = { a }: a` 62 | // 63 | // structured function argument 64 | // : `a` 65 | // : Function argument 66 | Argument::Pattern(pattern_args) => { 67 | let mut inner = String::new(); 68 | for pattern_arg in pattern_args { 69 | inner += &Argument::Flat(pattern_arg).format_argument(); 70 | } 71 | 72 | let indented = textwrap::indent(&inner, " "); 73 | 74 | format!( 75 | // The `:` creates another definition list of which `indented` is the term. 76 | "structured function argument\n\n: {}", 77 | // drop leading indentation on the first line, the `: ` serves this function 78 | // already. 79 | indented.trim_start() 80 | ) 81 | } 82 | } 83 | } 84 | } 85 | 86 | /// Since the first line starts with `: `, indent every other line by 2 spaces, so 87 | /// that the text aligns, to result in: 88 | /// 89 | /// : first line 90 | /// every other line 91 | fn handle_indentation(raw: &str) -> String { 92 | match raw.split_once('\n') { 93 | Some((first, rest)) => { 94 | format!("{}\n{}", first, textwrap::indent(rest, " ")) 95 | } 96 | None => raw.into(), 97 | } 98 | } 99 | 100 | /// Generate the identifier for CommonMark. 101 | /// ident is used as URL Encoded link to the function and has thus stricter rules (i.e. "' " in "lib.map' " is not allowed). 102 | pub(crate) fn get_identifier(prefix: &String, category: &String, name: &String) -> String { 103 | let name_prime = name.replace('\'', "-prime"); 104 | vec![prefix, category, &name_prime] 105 | .into_iter() 106 | .filter(|x| !x.is_empty()) 107 | .cloned() 108 | .collect::>() 109 | .join(".") 110 | } 111 | 112 | /// Generate the title for CommonMark. 113 | /// the title is the human-readable name of the function. 114 | pub(crate) fn get_title(prefix: &String, category: &String, name: &String) -> String { 115 | vec![prefix, category, name] 116 | .into_iter() 117 | .filter(|x| !x.is_empty()) 118 | .cloned() 119 | .collect::>() 120 | .join(".") 121 | } 122 | 123 | /// Represents a single manual section describing a library function. 124 | #[derive(Clone, Debug, Serialize)] 125 | pub struct ManualEntry { 126 | /// Prefix for the category (e.g. 'lib' or 'utils'). 127 | pub prefix: String, 128 | 129 | /// Name of the function category (e.g. 'strings', 'trivial', 'attrsets'). 130 | pub category: String, 131 | 132 | /// Location of the function. 133 | pub location: Option, 134 | 135 | /// Name of the section (used as the title). 136 | pub name: String, 137 | 138 | /// Type signature (if provided). This is not actually a checked 139 | /// type signature in any way. 140 | pub fn_type: Option, 141 | 142 | /// Primary description of the entry. Each entry is written as a 143 | /// separate paragraph. 144 | pub description: Vec, 145 | 146 | /// Usage example for the entry. 147 | pub example: Option, 148 | 149 | /// Arguments of the function. 150 | pub args: Vec, 151 | } 152 | 153 | impl ManualEntry { 154 | pub(crate) fn get_ident_title(&self) -> (String, String) { 155 | let ident = get_identifier(&self.prefix, &self.category, &self.name); 156 | let title = get_title(&self.prefix, &self.category, &self.name); 157 | (ident, title) 158 | } 159 | 160 | /// Write a single CommonMark entry for a documented Nix function. 161 | /// 162 | /// # Arguments 163 | /// 164 | /// - `anchor_prefix`: The prefix to use for the anchor links. 165 | /// In Nixpkgs this would be "function-library-". 166 | /// - `output`: The output string to append the CommonMark onto. 167 | pub fn write_section(self, anchor_prefix: &str, output: &mut String) -> String { 168 | let (ident, title) = self.get_ident_title(); 169 | output.push_str(&format!( 170 | "## `{}` {{#{}{}}}\n\n", 171 | title, anchor_prefix, ident 172 | )); 173 | 174 | // (type signature) 175 | if let Some(t) = &self.fn_type { 176 | if t.lines().count() > 1 { 177 | output.push_str(&format!("**Type**:\n```\n{}\n```\n\n", t)); 178 | } else { 179 | output.push_str(&format!("**Type**: `{}`\n\n", t)); 180 | } 181 | } 182 | 183 | // Primary doc string 184 | // TODO: Split paragraphs? 185 | for paragraph in &self.description { 186 | output.push_str(&format!("{}\n\n", paragraph)); 187 | } 188 | 189 | // Function argument names 190 | if !self.args.is_empty() { 191 | for arg in self.args { 192 | output.push_str(&format!("{}\n", arg.format_argument())); 193 | } 194 | } 195 | 196 | // Example program listing (if applicable) 197 | // 198 | // TODO: In grhmc's version there are multiple (named) 199 | // examples, how can this be achieved automatically? 200 | if let Some(example) = &self.example { 201 | output.push_str(&format!( 202 | "::: {{.example #{}example-{}}}\n", 203 | anchor_prefix, ident 204 | )); 205 | output.push_str(&format!("# `{}` usage example\n\n", title)); 206 | output.push_str(&format!("```nix\n{}\n```\n:::\n\n", example.trim())); 207 | } 208 | 209 | if let Some(loc) = self.location { 210 | output.push_str(&String::from(format!("Located at {loc}.\n\n"))); 211 | } 212 | 213 | output.to_string() 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/format.rs: -------------------------------------------------------------------------------- 1 | use textwrap::dedent; 2 | 3 | /// Ensure all lines in a multi-line doc-comments have the same indentation. 4 | /// 5 | /// Consider such a doc comment: 6 | /// 7 | /// ```nix 8 | /// { 9 | /// /* foo is 10 | /// the value: 11 | /// 10 12 | /// */ 13 | /// foo = 10; 14 | /// } 15 | /// ``` 16 | /// 17 | /// The parser turns this into: 18 | /// 19 | /// ``` 20 | /// foo is 21 | /// the value: 22 | /// 10 23 | /// ``` 24 | /// 25 | /// 26 | /// where the first line has no leading indentation, and all other lines have preserved their 27 | /// original indentation. 28 | /// 29 | /// What we want instead is: 30 | /// 31 | /// ``` 32 | /// foo is 33 | /// the value: 34 | /// 10 35 | /// ``` 36 | /// 37 | /// i.e. we want the whole thing to be dedented. To achieve this, we remove all leading whitespace 38 | /// from the first line, and remove all common whitespace from the rest of the string. 39 | pub fn handle_indentation(raw: &str) -> Option { 40 | let result: String = match raw.split_once('\n') { 41 | Some((first, rest)) => { 42 | format!("{}\n{}", first.trim_start(), dedent(rest)) 43 | } 44 | None => raw.into(), 45 | }; 46 | 47 | Some(result.trim().to_owned()).filter(|s| !s.is_empty()) 48 | } 49 | 50 | /// Shift down markdown headings 51 | /// 52 | /// Performs a line-wise matching to '# Heading ' 53 | /// 54 | /// Counts the current numbers of '#' and adds levels: [usize] to them 55 | /// levels := 1; gives 56 | /// '# Heading' -> '## Heading' 57 | /// 58 | /// Commonmark markdown has 6 levels of headings. Everything beyond that (e.g., H7) is not supported and may produce unexpected renderings. 59 | /// by default this function makes sure, headings don't exceed the H6 boundary. 60 | /// levels := 2; 61 | /// ... 62 | /// H4 -> H6 63 | /// H6 -> H6 64 | /// 65 | pub fn shift_headings(raw: &str, levels: usize) -> String { 66 | let mut result = String::new(); 67 | 68 | let mut curr_fence: Option<(usize, char)> = None; 69 | for raw_line in raw.split_inclusive('\n') { 70 | // Code blocks can only start with backticks or tildes 71 | // code fences can be indented by 0-3 spaces see commonmark spec. 72 | let fence_line = &trim_leading_whitespace(raw_line, 3); 73 | if fence_line.starts_with("```") | fence_line.starts_with("~~~") { 74 | let fence_info = get_fence(fence_line, true); 75 | if curr_fence.is_none() { 76 | // Start of code block 77 | curr_fence = fence_info; 78 | } else { 79 | // Possible end of code block. Ending fences cannot have info strings 80 | match (curr_fence, get_fence(fence_line, false)) { 81 | // End of code block must have the same fence type as the start (~~~ or ```) 82 | // Code blocks must be ended with at least the same number of backticks or tildes as the start fence 83 | (Some((start_count, start_char)), Some((end_count, end_char))) => { 84 | if start_count <= end_count && start_char == end_char { 85 | // End of code block (same fence as start) 86 | curr_fence = None; 87 | } 88 | } 89 | _ => {} 90 | }; 91 | } 92 | } 93 | 94 | // Remove up to 0-3 leading whitespaces. 95 | // If the line has 4 or more whitespaces it is not a heading according to commonmark spec. 96 | let heading_line = &trim_leading_whitespace(raw_line, 3); 97 | if curr_fence.is_none() && heading_line.starts_with('#') { 98 | let heading = handle_heading(heading_line, levels); 99 | result.push_str(&heading); 100 | } else { 101 | result.push_str(raw_line); 102 | } 103 | } 104 | result 105 | } 106 | 107 | /// Removes leading whitespaces from code fences if present 108 | /// However maximum of [max] whitespaces are removed. 109 | /// This is useful for code fences may have leading whitespaces (0-3). 110 | fn trim_leading_whitespace(input: &str, max: usize) -> String { 111 | let mut count = 0; 112 | input 113 | .trim_start_matches(|c: char| { 114 | if c.is_whitespace() && count < max { 115 | count += 1; 116 | true 117 | } else { 118 | false 119 | } 120 | }) 121 | .to_string() 122 | } 123 | /// A function that returns the count of a code fence line. 124 | /// Param [allow_info] allows to keep info strings in code fences. 125 | /// Ending fences cannot have info strings 126 | pub fn get_fence(line: &str, allow_info: bool) -> Option<(usize, char)> { 127 | let mut chars = line.chars(); 128 | if let Some(first_char) = chars.next() { 129 | if first_char == '`' || first_char == '~' { 130 | let mut count = 1; 131 | for ch in chars { 132 | if ch == first_char { 133 | // count the number of repeated code fence characters 134 | count += 1; 135 | } else { 136 | if !allow_info && ch != '\n' { 137 | // info string is not allowed this is not a code fence 138 | return None; 139 | } 140 | return Some((count, first_char)); 141 | } 142 | } 143 | return Some((count, first_char)); 144 | } 145 | } 146 | None 147 | } 148 | // Dumb heading parser. 149 | pub fn handle_heading(line: &str, levels: usize) -> String { 150 | let chars = line.chars(); 151 | 152 | let mut hashes = String::new(); 153 | let mut rest = String::new(); 154 | for char in chars { 155 | match char { 156 | '#' if rest.is_empty() => { 157 | // only collect hashes if no other tokens 158 | hashes.push(char) 159 | } 160 | _ => rest.push(char), 161 | } 162 | } 163 | let new_hashes = match hashes.len() + levels { 164 | // We reached the maximum heading size. 165 | 6.. => "#".repeat(6), 166 | _ => "#".repeat(hashes.len() + levels), 167 | }; 168 | 169 | format!("{new_hashes}{rest}") 170 | } 171 | -------------------------------------------------------------------------------- /src/legacy.rs: -------------------------------------------------------------------------------- 1 | use rnix::{ 2 | ast::{AstToken, Comment, Expr, Lambda, Param}, 3 | SyntaxKind, SyntaxNode, 4 | }; 5 | use rowan::ast::AstNode; 6 | use std::collections::HashMap; 7 | 8 | use crate::{ 9 | commonmark::{Argument, ManualEntry, SingleArg}, 10 | format::handle_indentation, 11 | get_identifier, retrieve_doc_comment, DocComment, 12 | }; 13 | 14 | #[derive(Debug)] 15 | pub struct LegacyDocItem { 16 | pub name: String, 17 | pub comment: DocComment, 18 | pub args: Vec, 19 | } 20 | 21 | impl LegacyDocItem { 22 | pub fn into_entry( 23 | self, 24 | prefix: &str, 25 | category: &str, 26 | locs: &HashMap, 27 | ) -> ManualEntry { 28 | let ident = get_identifier( 29 | &prefix.to_string(), 30 | &category.to_string(), 31 | &self.name.to_string(), 32 | ); 33 | 34 | ManualEntry { 35 | prefix: prefix.to_string(), 36 | category: category.to_string(), 37 | location: locs.get(&ident).cloned(), 38 | name: self.name, 39 | description: self 40 | .comment 41 | .doc 42 | .split("\n\n") 43 | .map(|s| s.to_string()) 44 | .collect(), 45 | fn_type: self.comment.doc_type, 46 | example: self.comment.example, 47 | args: self.args, 48 | } 49 | } 50 | } 51 | 52 | /// Retrieve documentation comments. 53 | pub fn retrieve_legacy_comment(node: &SyntaxNode, allow_line_comments: bool) -> Option { 54 | // if the current node has a doc comment it'll be immediately preceded by that comment, 55 | // or there will be a whitespace token and *then* the comment tokens before it. We merge 56 | // multiple line comments into one large comment if they are on adjacent lines for 57 | // documentation simplicity. 58 | let mut token = node.first_token()?.prev_token()?; 59 | if token.kind() == SyntaxKind::TOKEN_WHITESPACE { 60 | token = token.prev_token()?; 61 | } 62 | if token.kind() != SyntaxKind::TOKEN_COMMENT { 63 | return None; 64 | } 65 | // if we want to ignore line comments (eg because they may contain deprecation 66 | // comments on attributes) we'll backtrack to the first preceding multiline comment. 67 | while !allow_line_comments && token.text().starts_with('#') { 68 | token = token.prev_token()?; 69 | if token.kind() == SyntaxKind::TOKEN_WHITESPACE { 70 | token = token.prev_token()?; 71 | } 72 | if token.kind() != SyntaxKind::TOKEN_COMMENT { 73 | return None; 74 | } 75 | } 76 | 77 | if token.text().starts_with("/*") { 78 | return Some(Comment::cast(token)?.text().to_string()); 79 | } 80 | 81 | // backtrack to the start of the doc comment, allowing only adjacent line comments. 82 | // we don't care much about optimization here, doc comments aren't long enough for that. 83 | if token.text().starts_with('#') { 84 | let mut result = String::new(); 85 | while let Some(comment) = Comment::cast(token) { 86 | if !comment.syntax().text().starts_with('#') { 87 | break; 88 | } 89 | result.insert_str(0, comment.text().trim()); 90 | let ws = match comment.syntax().prev_token() { 91 | Some(t) if t.kind() == SyntaxKind::TOKEN_WHITESPACE => t, 92 | _ => break, 93 | }; 94 | // only adjacent lines continue a doc comment, empty lines do not. 95 | match ws.text().strip_prefix('\n') { 96 | Some(trail) if !trail.contains('\n') => result.insert(0, ' '), 97 | _ => break, 98 | } 99 | token = match ws.prev_token() { 100 | Some(c) => c, 101 | _ => break, 102 | }; 103 | } 104 | return Some(result); 105 | } 106 | 107 | None 108 | } 109 | 110 | /// Traverse directly chained nix lambdas and collect the identifiers of all lambda arguments 111 | /// until an unexpected AST node is encountered. 112 | pub fn collect_lambda_args_legacy(mut lambda: Lambda) -> Vec { 113 | let mut args = vec![]; 114 | 115 | loop { 116 | match lambda.param().unwrap() { 117 | // a variable, e.g. `x:` in `id = x: x` 118 | // Single args are not supported by RFC145, due to ambiguous placement rules. 119 | Param::IdentParam(id) => { 120 | args.push(Argument::Flat(SingleArg { 121 | name: id.to_string(), 122 | doc: handle_indentation( 123 | &retrieve_legacy_comment(id.syntax(), true).unwrap_or_default(), 124 | ), 125 | })); 126 | } 127 | // an ident in a pattern, e.g. `a` in `foo = { a }: a` 128 | Param::Pattern(pat) => { 129 | // collect doc-comments for each lambda formal too 130 | // Lambda formals are supported by RFC145 131 | let pattern_vec: Vec<_> = pat 132 | .pat_entries() 133 | .map(|entry| SingleArg { 134 | name: entry.ident().unwrap().to_string(), 135 | doc: handle_indentation( 136 | &retrieve_doc_comment(entry.syntax(), Some(1)) 137 | .or(retrieve_legacy_comment(entry.syntax(), true)) 138 | .unwrap_or_default(), 139 | ), 140 | }) 141 | .collect(); 142 | 143 | args.push(Argument::Pattern(pattern_vec)); 144 | } 145 | } 146 | 147 | // Curried or not? 148 | match lambda.body() { 149 | Some(Expr::Lambda(inner)) => lambda = inner, 150 | _ => break, 151 | } 152 | } 153 | 154 | args 155 | } 156 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2018 Vincent Ambo 2 | // 3 | // nixdoc is free software: you can redistribute it and/or modify it 4 | // under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | //! This tool generates CommonMark from a Nix file defining library 17 | //! functions, such as the files in `lib/` in the nixpkgs repository. 18 | //! 19 | //! TODO: 20 | //! * extract function argument names 21 | //! * extract line number & add it to generated output 22 | //! * figure out how to specify examples (& leading whitespace?!) 23 | 24 | mod comment; 25 | mod commonmark; 26 | mod format; 27 | mod legacy; 28 | #[cfg(test)] 29 | mod test; 30 | 31 | use crate::{format::handle_indentation, legacy::retrieve_legacy_comment}; 32 | 33 | use self::comment::get_expr_docs; 34 | use self::commonmark::*; 35 | use format::shift_headings; 36 | use legacy::{collect_lambda_args_legacy, LegacyDocItem}; 37 | use rnix::{ 38 | ast::{Attr, AttrpathValue, Expr, Inherit, LetIn}, 39 | SyntaxKind, SyntaxNode, 40 | }; 41 | use rowan::{ast::AstNode, WalkEvent}; 42 | use std::fs; 43 | 44 | use serde::Serialize; 45 | use std::collections::HashMap; 46 | 47 | use clap::Parser; 48 | use std::path::PathBuf; 49 | 50 | /// Command line arguments for nixdoc 51 | #[derive(Debug, Parser)] 52 | #[command(author, version, about)] 53 | struct Options { 54 | /// Prefix for the category (e.g. 'lib' or 'utils'). 55 | #[arg(short, long, default_value_t = String::from("lib"))] 56 | prefix: String, 57 | 58 | #[arg(long, default_value_t = String::from("function-library-"))] 59 | anchor_prefix: String, 60 | 61 | /// Whether to output JSON. 62 | #[arg(short, long, default_value_t = false)] 63 | json_output: bool, 64 | 65 | /// Name of the function category (e.g. 'strings', 'attrsets'). 66 | #[arg(short, long)] 67 | category: String, 68 | 69 | /// Description of the function category. 70 | #[arg(short, long)] 71 | description: String, 72 | 73 | /// Nix file to process. 74 | #[arg(short, long)] 75 | file: PathBuf, 76 | 77 | /// Path to a file containing location data as JSON. 78 | #[arg(short, long)] 79 | locs: Option, 80 | } 81 | 82 | #[derive(Debug)] 83 | struct DocComment { 84 | /// Primary documentation string. 85 | doc: String, 86 | 87 | /// Optional type annotation for the thing being documented. 88 | /// This is only available as legacy feature 89 | doc_type: Option, 90 | 91 | /// Usage example(s) (interpreted as a single code block) 92 | /// This is only available as legacy feature 93 | example: Option, 94 | } 95 | 96 | #[derive(Debug)] 97 | struct DocItem { 98 | name: String, 99 | comment: DocComment, 100 | } 101 | 102 | #[derive(Debug, Serialize)] 103 | struct JsonFormat { 104 | version: u32, 105 | entries: Vec, 106 | } 107 | 108 | enum DocItemOrLegacy { 109 | LegacyDocItem(LegacyDocItem), 110 | DocItem(DocItem), 111 | } 112 | 113 | /// Returns a rfc145 doc-comment if one is present 114 | pub fn retrieve_doc_comment(node: &SyntaxNode, shift_headings_by: Option) -> Option { 115 | let doc_comment = get_expr_docs(node); 116 | 117 | doc_comment.map(|doc_comment| { 118 | shift_headings( 119 | &handle_indentation(&doc_comment).unwrap_or(String::new()), 120 | // H1 to H4 can be used in the doc-comment with the current rendering. 121 | // They will be shifted to H3, H6 122 | // H1 and H2 are currently used by the outer rendering. (category and function name) 123 | shift_headings_by.unwrap_or(2), 124 | ) 125 | }) 126 | } 127 | 128 | /// Transforms an AST node into a `DocItem` if it has a leading 129 | /// documentation comment. 130 | fn retrieve_doc_item(node: &AttrpathValue) -> Option { 131 | let ident = node.attrpath().unwrap(); 132 | // TODO this should join attrs() with '.' to handle whitespace, dynamic attrs and string 133 | // attrs. none of these happen in nixpkgs lib, and the latter two should probably be 134 | // rejected entirely. 135 | let item_name = ident.to_string(); 136 | 137 | let doc_comment = retrieve_doc_comment(node.syntax(), Some(2)); 138 | match doc_comment { 139 | Some(comment) => Some(DocItemOrLegacy::DocItem(DocItem { 140 | name: item_name, 141 | comment: DocComment { 142 | doc: comment, 143 | doc_type: None, 144 | example: None, 145 | }, 146 | })), 147 | // Fallback to legacy comment is there is no doc_comment 148 | None => { 149 | let comment = retrieve_legacy_comment(node.syntax(), false)?; 150 | Some(DocItemOrLegacy::LegacyDocItem(LegacyDocItem { 151 | name: item_name, 152 | comment: parse_doc_comment(&comment), 153 | args: vec![], 154 | })) 155 | } 156 | } 157 | } 158 | 159 | /// Dumb, mutable, hacky doc comment "parser". 160 | fn parse_doc_comment(raw: &str) -> DocComment { 161 | enum ParseState { 162 | Doc, 163 | Type, 164 | Example, 165 | } 166 | 167 | let mut state = ParseState::Doc; 168 | 169 | // Split the string into three parts, docs, type and example 170 | let mut doc_str = String::new(); 171 | let mut type_str = String::new(); 172 | let mut example_str = String::new(); 173 | 174 | for line in raw.split_inclusive('\n') { 175 | let trimmed_line = line.trim(); 176 | if let Some(suffix) = trimmed_line.strip_prefix("Type:") { 177 | state = ParseState::Type; 178 | type_str.push_str(suffix); 179 | type_str.push('\n'); 180 | } else if let Some(suffix) = trimmed_line.strip_prefix("Example:") { 181 | state = ParseState::Example; 182 | example_str.push_str(suffix); 183 | example_str.push('\n'); 184 | } else { 185 | match state { 186 | ParseState::Doc => doc_str.push_str(line), 187 | ParseState::Type => type_str.push_str(line), 188 | ParseState::Example => example_str.push_str(line), 189 | } 190 | } 191 | } 192 | 193 | DocComment { 194 | doc: handle_indentation(&doc_str).unwrap_or(String::new()), 195 | doc_type: handle_indentation(&type_str), 196 | example: handle_indentation(&example_str), 197 | } 198 | } 199 | 200 | /// Traverse the arena from a top-level SetEntry and collect, where 201 | /// possible: 202 | /// 203 | /// 1. The identifier of the set entry itself. 204 | /// 2. The attached doc comment on the entry. 205 | /// 3. The argument names of any curried functions (pattern functions 206 | /// not yet supported). 207 | fn collect_entry_information(entry: AttrpathValue) -> Option { 208 | let doc_item = retrieve_doc_item(&entry)?; 209 | 210 | match doc_item { 211 | DocItemOrLegacy::LegacyDocItem(v) => { 212 | if let Some(Expr::Lambda(l)) = entry.value() { 213 | Some(LegacyDocItem { 214 | args: collect_lambda_args_legacy(l), 215 | ..v 216 | }) 217 | } else { 218 | Some(v) 219 | } 220 | } 221 | // Convert DocItems into legacyItem for markdown rendering 222 | DocItemOrLegacy::DocItem(v) => Some(LegacyDocItem { 223 | args: vec![], 224 | name: v.name, 225 | comment: v.comment, 226 | }), 227 | } 228 | } 229 | 230 | // a binding is an assignment, which can take place in an attrset 231 | // - as attributes 232 | // - as inherits 233 | fn collect_bindings( 234 | node: &SyntaxNode, 235 | prefix: &str, 236 | category: &str, 237 | locs: &HashMap, 238 | scope: HashMap, 239 | ) -> Vec { 240 | for ev in node.preorder() { 241 | match ev { 242 | WalkEvent::Enter(n) if n.kind() == SyntaxKind::NODE_ATTR_SET => { 243 | let mut entries = vec![]; 244 | for child in n.children() { 245 | if let Some(apv) = AttrpathValue::cast(child.clone()) { 246 | entries.extend( 247 | collect_entry_information(apv) 248 | .map(|di| di.into_entry(prefix, category, locs)), 249 | ); 250 | } else if let Some(inh) = Inherit::cast(child) { 251 | // `inherit (x) ...` needs much more handling than we can 252 | // reasonably do here 253 | if inh.from().is_some() { 254 | continue; 255 | } 256 | entries.extend(inh.attrs().filter_map(|a| match a { 257 | Attr::Ident(i) => scope.get(&i.syntax().text().to_string()).cloned(), 258 | // ignore non-ident keys. these aren't useful as lib 259 | // functions in general anyway. 260 | _ => None, 261 | })); 262 | } 263 | } 264 | return entries; 265 | } 266 | _ => (), 267 | } 268 | } 269 | 270 | vec![] 271 | } 272 | 273 | // Main entrypoint for collection 274 | // TODO: document 275 | fn collect_entries( 276 | root: rnix::Root, 277 | prefix: &str, 278 | category: &str, 279 | locs: &HashMap, 280 | ) -> Vec { 281 | // we will look into the top-level let and its body for function docs. 282 | // we only need a single level of scope for this. 283 | // since only the body can export a function we don't need to implement 284 | // mutually recursive resolution. 285 | let mut preorder = root.syntax().preorder(); 286 | while let Some(ev) = preorder.next() { 287 | match ev { 288 | // Skip patterns. See test/patterns.nix for the reason why. 289 | WalkEvent::Enter(n) if n.kind() == SyntaxKind::NODE_PATTERN => { 290 | preorder.skip_subtree(); 291 | } 292 | WalkEvent::Enter(n) if n.kind() == SyntaxKind::NODE_LET_IN => { 293 | return collect_bindings( 294 | LetIn::cast(n.clone()).unwrap().body().unwrap().syntax(), 295 | prefix, 296 | category, 297 | locs, 298 | n.children() 299 | .filter_map(AttrpathValue::cast) 300 | .filter_map(collect_entry_information) 301 | .map(|di| (di.name.to_string(), di.into_entry(prefix, category, locs))) 302 | .collect(), 303 | ); 304 | } 305 | WalkEvent::Enter(n) if n.kind() == SyntaxKind::NODE_ATTR_SET => { 306 | return collect_bindings(&n, prefix, category, locs, Default::default()); 307 | } 308 | _ => (), 309 | } 310 | } 311 | 312 | vec![] 313 | } 314 | 315 | fn retrieve_description(nix: &rnix::Root, description: &str, category: &str) -> String { 316 | if description.is_empty() && category.is_empty() { 317 | return String::new(); 318 | } 319 | format!( 320 | "# {} {{#sec-functions-library-{}}}\n{}\n", 321 | description, 322 | category, 323 | &nix.syntax() 324 | .first_child() 325 | .and_then(|node| retrieve_doc_comment(&node, Some(1)) 326 | .or(retrieve_legacy_comment(&node, false))) 327 | .and_then(|doc_item| handle_indentation(&doc_item)) 328 | .unwrap_or_default() 329 | ) 330 | } 331 | 332 | fn main_with_options(opts: Options) -> String { 333 | let src = fs::read_to_string(&opts.file).unwrap(); 334 | let locs = match opts.locs { 335 | None => Default::default(), 336 | Some(p) => fs::read_to_string(p) 337 | .map_err(|e| e.to_string()) 338 | .and_then(|json| serde_json::from_str(&json).map_err(|e| e.to_string())) 339 | .expect("could not read location information"), 340 | }; 341 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 342 | let description = retrieve_description(&nix, &opts.description, &opts.category); 343 | 344 | let entries = collect_entries(nix, &opts.prefix, &opts.category, &locs); 345 | 346 | if opts.json_output { 347 | let json_string = match serde_json::to_string(&JsonFormat { 348 | version: 1, 349 | entries, 350 | }) { 351 | Ok(json) => json, 352 | Err(error) => panic!("Problem converting entries to JSON: {error:?}"), 353 | }; 354 | json_string 355 | } else { 356 | // TODO: move this to commonmark.rs 357 | let mut output = description + "\n"; 358 | 359 | for entry in entries { 360 | entry.write_section(opts.anchor_prefix.as_str(), &mut output); 361 | } 362 | output 363 | } 364 | } 365 | 366 | fn main() { 367 | let opts = Options::parse(); 368 | let output = main_with_options(opts); 369 | println!("{}", output) 370 | } 371 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__arg_formatting.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/main.rs 3 | expression: output 4 | --- 5 | ## `lib.options.fn` {#function-library-lib.options.fn} 6 | 7 | documented function 8 | 9 | `a` 10 | 11 | : single arugment 12 | 13 | 14 | structured function argument 15 | 16 | : `default` 17 | 18 | : documented argument 19 | 20 | `example` 21 | 22 | : i like this argument. another! 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__commonmark.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | # Heading 1 6 | 7 | This Markdown includes a variety of elements that you might find in a document parsed to an AST by a Markdown parser following the CommonMark specification. 8 | Feel free to modify or expand upon it based on your specific needs or to explore additional Markdown features. 9 | 10 | ## Heading 2 11 | 12 | ### Heading 3 13 | 14 | #### Heading 4 15 | 16 | ##### Heading 5 17 | 18 | This is a paragraph with some **bold text** and _italic text_. 19 | 20 | > This is a blockquote. 21 | 22 | - This is 23 | - an unordered 24 | - list 25 | 26 | 1. This is 27 | 2. an ordered 28 | 3. list 29 | 30 | `Inline code` spans are also supported. 31 | 32 | ```bash {#example .class} 33 | # This is a code block 34 | echo "Hello, Markdown!" 35 | ``` 36 | 37 | Here is a horizontal rule: 38 | 39 | --- 40 | 41 | ### Links and Images 42 | 43 | [This is a link](https://example.com) 44 | 45 | ![This is an image](https://example.com/image.png "Image Title") 46 | 47 | ### Tables 48 | 49 | | Syntax | Description | 50 | | --------- | ----------- | 51 | | Header | Title | 52 | | Paragraph | Text | 53 | 54 | ### Footnotes 55 | 56 | Here is a text with a footnote[^1]. 57 | 58 | [^1]: This is the footnote. 59 | 60 | ### Inline HTML 61 | 62 | This is bold text using HTML 63 | 64 |
65 | This is a div with red text. 66 |
67 | 68 | ### Task list 69 | 70 | - [x] This is a completed task 71 | - [ ] This is an uncompleted task 72 | 73 | ### Markdown-it-py extensions 74 | 75 | ### Fenced div with attributes 76 | 77 | ::: {#customDiv .customStyle key="value"} 78 | This is a Pandoc-style fenced div with attributes. 79 | ::: 80 | 81 | :::{#ex-makeScope .example} 82 | #### Create an interdependent package set on top of `pkgs` 83 | 84 | The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument. 85 | 86 | ```nix 87 | let 88 | pkgs = import { }; 89 | in 90 | pkgs.lib.makeScope pkgs.newScope (self: { 91 | foo = self.callPackage ./foo.nix { }; 92 | bar = self.callPackage ./bar.nix { }; 93 | }) 94 | ``` 95 | 96 | evaluates to 97 | 98 | ```nix 99 | { 100 | callPackage = «lambda»; 101 | newScope = «lambda»; 102 | overrideScope = «lambda»; 103 | packages = «lambda»; 104 | foo = «derivation»; 105 | bar = «derivation»; 106 | } 107 | ``` 108 | ::: 109 | 110 | ### Heading anchors 111 | 112 | #### Simple {#some-id} 113 | 114 | #### With attributes {#some-other-id .customClass style="color:blue;"} 115 | 116 | This heading includes both an anchor and CSS attributes. 117 | 118 | ### Definition List 119 | 120 | Term 1 121 | : Definition 1 122 | 123 | Term 2 124 | : Definition 2 with a **bold** aspect. 125 | 126 | Parent Term 127 | : Parent Definition 128 | 129 | Nested Term 1 130 | : Nested Definition 1 131 | 132 | Nested Term 2 133 | : Nested Definition 2 134 | 135 | ::: {.important} 136 | **Note:** 137 | : This is an important note inside a custom styled div. 138 | ::: 139 | 140 | ### Codeblocks 141 | 142 | ```python 143 | # This is a Python code example 144 | def hello_world(): 145 | print("Hello, world!") 146 | ``` 147 | 148 | Codeblock with attributes 149 | 150 | ```python {#codeExample .highlighted style="background-color: #f0f0f0;"} 151 | # This is a Python code example 152 | def hello_world(): 153 | print("Hello, world!") 154 | ``` 155 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__description_of_lib_debug.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/main.rs 3 | expression: output 4 | --- 5 | # Debug {#sec-functions-library-debug} 6 | Collection of functions useful for debugging 7 | broken nix expressions. 8 | 9 | * `trace`-like functions take two values, print 10 | the first to stderr and return the second. 11 | * `traceVal`-like functions take one argument 12 | which both printed and returned. 13 | * `traceSeq`-like functions fully evaluate their 14 | traced value before printing (not just to “weak 15 | head normal form” like trace does by default). 16 | * Functions that end in `-Fn` take an additional 17 | function as their first argument, which is applied 18 | to the traced value before it is printed. 19 | 20 | ## `lib.debug.traceIf` {#function-library-lib.debug.traceIf} 21 | 22 | **Type**: `traceIf :: bool -> string -> a -> a` 23 | 24 | Conditionally trace the supplied message, based on a predicate. 25 | 26 | `pred` 27 | 28 | : Predicate to check 29 | 30 | 31 | `msg` 32 | 33 | : Message that should be traced 34 | 35 | 36 | `x` 37 | 38 | : Value to return 39 | 40 | 41 | ::: {.example #function-library-example-lib.debug.traceIf} 42 | # `lib.debug.traceIf` usage example 43 | 44 | ```nix 45 | traceIf true "hello" 3 46 | trace: hello 47 | => 3 48 | ``` 49 | ::: 50 | 51 | ## `lib.debug.traceValFn` {#function-library-lib.debug.traceValFn} 52 | 53 | **Type**: `traceValFn :: (a -> b) -> a -> a` 54 | 55 | Trace the supplied value after applying a function to it, and 56 | return the original value. 57 | 58 | `f` 59 | 60 | : Function to apply 61 | 62 | 63 | `x` 64 | 65 | : Value to trace and return 66 | 67 | 68 | ::: {.example #function-library-example-lib.debug.traceValFn} 69 | # `lib.debug.traceValFn` usage example 70 | 71 | ```nix 72 | traceValFn (v: "mystring ${v}") "foo" 73 | trace: mystring foo 74 | => "foo" 75 | ``` 76 | ::: 77 | 78 | ## `lib.debug.traceVal` {#function-library-lib.debug.traceVal} 79 | 80 | **Type**: `traceVal :: a -> a` 81 | 82 | Trace the supplied value and return it. 83 | 84 | ::: {.example #function-library-example-lib.debug.traceVal} 85 | # `lib.debug.traceVal` usage example 86 | 87 | ```nix 88 | traceVal 42 89 | # trace: 42 90 | => 42 91 | ``` 92 | ::: 93 | 94 | ## `lib.debug.traceSeq` {#function-library-lib.debug.traceSeq} 95 | 96 | **Type**: `traceSeq :: a -> b -> b` 97 | 98 | `builtins.trace`, but the value is `builtins.deepSeq`ed first. 99 | 100 | `x` 101 | 102 | : The value to trace 103 | 104 | 105 | `y` 106 | 107 | : The value to return 108 | 109 | 110 | ::: {.example #function-library-example-lib.debug.traceSeq} 111 | # `lib.debug.traceSeq` usage example 112 | 113 | ```nix 114 | trace { a.b.c = 3; } null 115 | trace: { a = ; } 116 | => null 117 | traceSeq { a.b.c = 3; } null 118 | trace: { a = { b = { c = 3; }; }; } 119 | => null 120 | ``` 121 | ::: 122 | 123 | ## `lib.debug.traceSeqN` {#function-library-lib.debug.traceSeqN} 124 | 125 | **Type**: `traceSeqN :: Int -> a -> b -> b` 126 | 127 | Like `traceSeq`, but only evaluate down to depth n. 128 | This is very useful because lots of `traceSeq` usages 129 | lead to an infinite recursion. 130 | 131 | `depth` 132 | 133 | : Function argument 134 | 135 | 136 | `x` 137 | 138 | : Function argument 139 | 140 | 141 | `y` 142 | 143 | : Function argument 144 | 145 | 146 | ::: {.example #function-library-example-lib.debug.traceSeqN} 147 | # `lib.debug.traceSeqN` usage example 148 | 149 | ```nix 150 | traceSeqN 2 { a.b.c = 3; } null 151 | trace: { a = { b = {…}; }; } 152 | => null 153 | ``` 154 | ::: 155 | 156 | ## `lib.debug.traceValSeqFn` {#function-library-lib.debug.traceValSeqFn} 157 | 158 | A combination of `traceVal` and `traceSeq` that applies a 159 | provided function to the value to be traced after `deepSeq`ing 160 | it. 161 | 162 | `f` 163 | 164 | : Function to apply 165 | 166 | 167 | `v` 168 | 169 | : Value to trace 170 | 171 | 172 | ## `lib.debug.traceValSeq` {#function-library-lib.debug.traceValSeq} 173 | 174 | A combination of `traceVal` and `traceSeq`. 175 | 176 | ## `lib.debug.traceValSeqNFn` {#function-library-lib.debug.traceValSeqNFn} 177 | 178 | A combination of `traceVal` and `traceSeqN` that applies a 179 | provided function to the value to be traced. 180 | 181 | `f` 182 | 183 | : Function to apply 184 | 185 | 186 | `depth` 187 | 188 | : Function argument 189 | 190 | 191 | `v` 192 | 193 | : Value to trace 194 | 195 | 196 | ## `lib.debug.traceValSeqN` {#function-library-lib.debug.traceValSeqN} 197 | 198 | A combination of `traceVal` and `traceSeqN`. 199 | 200 | ## `lib.debug.traceFnSeqN` {#function-library-lib.debug.traceFnSeqN} 201 | 202 | Trace the input and output of a function `f` named `name`, 203 | both down to `depth`. 204 | 205 | This is useful for adding around a function call, 206 | to see the before/after of values as they are transformed. 207 | 208 | `depth` 209 | 210 | : Function argument 211 | 212 | 213 | `name` 214 | 215 | : Function argument 216 | 217 | 218 | `f` 219 | 220 | : Function argument 221 | 222 | 223 | `v` 224 | 225 | : Function argument 226 | 227 | 228 | ::: {.example #function-library-example-lib.debug.traceFnSeqN} 229 | # `lib.debug.traceFnSeqN` usage example 230 | 231 | ```nix 232 | traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } 233 | trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; } 234 | => { a.b.c = 3; } 235 | ``` 236 | ::: 237 | 238 | ## `lib.debug.runTests` {#function-library-lib.debug.runTests} 239 | 240 | **Type**: 241 | ``` 242 | runTests :: { 243 | tests = [ String ]; 244 | ${testName} :: { 245 | expr :: a; 246 | expected :: a; 247 | }; 248 | } 249 | -> 250 | [ 251 | { 252 | name :: String; 253 | expected :: a; 254 | result :: a; 255 | } 256 | ] 257 | ``` 258 | 259 | Evaluates a set of tests. 260 | 261 | A test is an attribute set `{expr, expected}`, 262 | denoting an expression and its expected result. 263 | 264 | The result is a `list` of __failed tests__, each represented as 265 | `{name, expected, result}`, 266 | 267 | - expected 268 | - What was passed as `expected` 269 | - result 270 | - The actual `result` of the test 271 | 272 | Used for regression testing of the functions in lib; see 273 | tests.nix for more examples. 274 | 275 | Important: Only attributes that start with `test` are executed. 276 | 277 | - If you want to run only a subset of the tests add the attribute `tests = ["testName"];` 278 | 279 | `tests` 280 | 281 | : Tests to run 282 | 283 | 284 | ::: {.example #function-library-example-lib.debug.runTests} 285 | # `lib.debug.runTests` usage example 286 | 287 | ```nix 288 | runTests { 289 | testAndOk = { 290 | expr = lib.and true false; 291 | expected = false; 292 | }; 293 | testAndFail = { 294 | expr = lib.and true false; 295 | expected = true; 296 | }; 297 | } 298 | -> 299 | [ 300 | { 301 | name = "testAndFail"; 302 | expected = true; 303 | result = false; 304 | } 305 | ] 306 | ``` 307 | ::: 308 | 309 | ## `lib.debug.testAllTrue` {#function-library-lib.debug.testAllTrue} 310 | 311 | Create a test assuming that list elements are `true`. 312 | 313 | `expr` 314 | 315 | : Function argument 316 | 317 | 318 | ::: {.example #function-library-example-lib.debug.testAllTrue} 319 | # `lib.debug.testAllTrue` usage example 320 | 321 | ```nix 322 | { testX = allTrue [ true ]; } 323 | ``` 324 | ::: 325 | 326 | 327 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__doc_comment.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | ## `lib.debug.nixdoc` {#function-library-lib.debug.nixdoc} 6 | 7 | **Type**: `This is a parsed type` 8 | 9 | nixdoc-legacy comment 10 | 11 | ::: {.example #function-library-example-lib.debug.nixdoc} 12 | # `lib.debug.nixdoc` usage example 13 | 14 | ```nix 15 | This is a parsed example 16 | ``` 17 | ::: 18 | 19 | ## `lib.debug.rfc-style` {#function-library-lib.debug.rfc-style} 20 | 21 | doc comment in markdown format 22 | 23 | ## `lib.debug.foo` {#function-library-lib.debug.foo} 24 | 25 | Comment 26 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__doc_comment_no_duplicate_arguments.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | # Debug {#sec-functions-library-debug} 6 | 7 | 8 | ## `lib.debug.old` {#function-library-lib.debug.old} 9 | 10 | nixdoc comment 11 | 12 | `arg` 13 | 14 | : Should be visible 15 | 16 | 17 | ## `lib.debug.omited` {#function-library-lib.debug.omited} 18 | 19 | Doc-comment 20 | 21 | ## `lib.debug.multiple` {#function-library-lib.debug.multiple} 22 | 23 | Doc-comment 24 | 25 | ## `lib.debug.argumentTest` {#function-library-lib.debug.argumentTest} 26 | 27 | Doc-comment before the lamdba causes the whole 28 | lambda including its arguments to switch to doc-comments ONLY rendering 29 | 30 | ## `lib.debug.legacyArgumentTest` {#function-library-lib.debug.legacyArgumentTest} 31 | 32 | Legacy comments allow to use any 33 | form of comments for the lambda arguments/formals 34 | 35 | structured function argument 36 | 37 | : `formal1` 38 | 39 | : Legacy line comment 40 | 41 | `formal2` 42 | 43 | : Legacy Block 44 | 45 | `formal3` 46 | 47 | : Legacy 48 | multiline 49 | comment 50 | 51 | `formal4` 52 | 53 | : doc-comment style 54 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__doc_comment_section_description.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | # Debug {#sec-functions-library-debug} 6 | Markdown section heading 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__headings.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | ### h1-heading 6 | 7 | #### h2-heading 8 | 9 | 3 leading whitespaces are okay for headings 10 | 11 | #### h2 heading 12 | 13 | # code block 14 | 15 | 16 | #### h2-heading-with-id {#some-id} 17 | 18 | Indented code block 19 | 20 | # Code comment 21 | a = 1; 22 | 23 | ##### h3-heading 24 | 25 | ```nix 26 | # A comment should not be shifted 27 | ``` 28 | 29 | ##### annother heading 30 | 31 | ``` 32 | # Some pseudocode 33 | map a from b -> 1 34 | ``` 35 | 36 | ##### indented (0-3) fences 37 | 38 | 3 leading whitespaces are okay for code fences 39 | 40 | ``` lang info 41 | # Some pseudocode 42 | map a from b -> 1 43 | ``` 44 | 45 | ##### indented (0-3) fences asymmetric 46 | 47 | ``` 48 | # Some pseudocode 49 | map a from b -> 1 50 | ``` 51 | 52 | ##### More closing fences than opening 53 | 54 | ```` 55 | # Some pseudocode 56 | map a from b -> 1 57 | ``````` 58 | 59 | ##### Some heading 60 | 61 | ````nix 62 | /** 63 | ```nix 64 | # A nested comment should not be shifted 65 | ``` 66 | */ 67 | 1 68 | # A comment 69 | ```` 70 | 71 | ###### h4-heading 72 | 73 | Nested tilde fences 74 | 75 | ~~~~~nix 76 | /* 77 | ~~~~nix 78 | /** 79 | ~~~nix 80 | # A nested comment should not be shifted 81 | 42 82 | ~~~ 83 | */ 84 | 1 85 | # A nested comment ^ 86 | ~~~~ 87 | */ 88 | # A comment ^ 89 | foo 90 | ~~~~~ 91 | 92 | ###### h5-heading 93 | 94 | Mixed fences 95 | 96 | ~~~nix 97 | /** 98 | ```nix 99 | # A nested comment should not be shifted 100 | ``` 101 | */ 102 | 1 103 | # A comment 104 | ~~~ 105 | 106 | ###### h6-heading 107 | 108 | This should be h6 as well 109 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__inherited_exports.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/main.rs 3 | expression: output 4 | --- 5 | ## `lib.let.concatStrings` {#function-library-lib.let.concatStrings} 6 | 7 | **Type**: `concatStrings :: [string] -> string` 8 | 9 | Concatenate a list of strings. 10 | 11 | ::: {.example #function-library-example-lib.let.concatStrings} 12 | # `lib.let.concatStrings` usage example 13 | 14 | ```nix 15 | concatStrings ["foo" "bar"] 16 | => "foobar" 17 | ``` 18 | ::: 19 | 20 | ## `lib.let.foo2` {#function-library-lib.let.foo2} 21 | 22 | this should be found 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__json_output.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | assertion_line: 39 4 | expression: output 5 | --- 6 | {"version":1,"entries":[{"prefix":"lib","category":"strings","location":"[lib/strings.nix:49](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L49) in ``","name":"concatStrings","fn_type":"concatStrings :: [string] -> string","description":["Concatenate a list of strings."],"example":"concatStrings [\"foo\" \"bar\"]\n=> \"foobar\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:59](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L59) in ``","name":"concatMapStrings","fn_type":"concatMapStrings :: (a -> string) -> [a] -> string","description":["Map a function over a list and concatenate the resulting strings."],"example":"concatMapStrings (x: \"a\" + x) [\"foo\" \"bar\"]\n=> \"afooabar\"","args":[{"Flat":{"name":"f","doc":null}},{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:70](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L70) in ``","name":"concatImapStrings","fn_type":"concatImapStrings :: (int -> a -> string) -> [a] -> string","description":["Like `concatMapStrings` except that the f functions also gets the\nposition as a parameter."],"example":"concatImapStrings (pos: x: \"${toString pos}-${x}\") [\"foo\" \"bar\"]\n=> \"1-foo2-bar\"","args":[{"Flat":{"name":"f","doc":null}},{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:80](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L80) in ``","name":"intersperse","fn_type":"intersperse :: a -> [a] -> [a]","description":["Place an element between each element of a list"],"example":"intersperse \"/\" [\"usr\" \"local\" \"bin\"]\n=> [\"usr\" \"/\" \"local\" \"/\" \"bin\"].","args":[{"Flat":{"name":"separator","doc":"Separator to add between elements"}},{"Flat":{"name":"list","doc":"Input list"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:97](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L97) in ``","name":"concatStringsSep","fn_type":"concatStringsSep :: string -> [string] -> string","description":["Concatenate a list of strings with a separator between each element"],"example":"concatStringsSep \"/\" [\"usr\" \"local\" \"bin\"]\n=> \"usr/local/bin\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:110](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L110) in ``","name":"concatMapStringsSep","fn_type":"concatMapStringsSep :: string -> (a -> string) -> [a] -> string","description":["Maps a function over a list of strings and then concatenates the\nresult with the specified separator interspersed between\nelements."],"example":"concatMapStringsSep \"-\" (x: toUpper x) [\"foo\" \"bar\" \"baz\"]\n=> \"FOO-BAR-BAZ\"","args":[{"Flat":{"name":"sep","doc":"Separator to add between elements"}},{"Flat":{"name":"f","doc":"Function to map over the list"}},{"Flat":{"name":"list","doc":"List of input strings"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:127](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L127) in ``","name":"concatImapStringsSep","fn_type":"concatIMapStringsSep :: string -> (int -> a -> string) -> [a] -> string","description":["Same as `concatMapStringsSep`, but the mapping function\nadditionally receives the position of its argument."],"example":"concatImapStringsSep \"-\" (pos: x: toString (x / pos)) [ 6 6 6 ]\n=> \"6-3-2\"","args":[{"Flat":{"name":"sep","doc":"Separator to add between elements"}},{"Flat":{"name":"f","doc":"Function that receives elements and their positions"}},{"Flat":{"name":"list","doc":"List of input strings"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:144](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L144) in ``","name":"concatLines","fn_type":"concatLines :: [string] -> string","description":["Concatenate a list of strings, adding a newline at the end of each one.\nDefined as `concatMapStrings (s: s + \"\\n\")`."],"example":"concatLines [ \"foo\" \"bar\" ]\n=> \"foo\\nbar\\n\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:157](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L157) in ``","name":"makeSearchPath","fn_type":"makeSearchPath :: string -> [string] -> string","description":["Construct a Unix-style, colon-separated search path consisting of\nthe given `subDir` appended to each of the given paths."],"example":"makeSearchPath \"bin\" [\"/root\" \"/usr\" \"/usr/local\"]\n=> \"/root/bin:/usr/bin:/usr/local/bin\"\nmakeSearchPath \"bin\" [\"\"]\n=> \"/bin\"","args":[{"Flat":{"name":"subDir","doc":"Directory name to append"}},{"Flat":{"name":"paths","doc":"List of base paths"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:175](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L175) in ``","name":"makeSearchPathOutput","fn_type":"string -> string -> [package] -> string","description":["Construct a Unix-style search path by appending the given\n`subDir` to the specified `output` of each of the packages. If no\noutput by the given name is found, fallback to `.out` and then to\nthe default."],"example":"makeSearchPathOutput \"dev\" \"bin\" [ pkgs.openssl pkgs.zlib ]\n=> \"/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin\"","args":[{"Flat":{"name":"output","doc":"Package output to use"}},{"Flat":{"name":"subDir","doc":"Directory name to append"}},{"Flat":{"name":"pkgs","doc":"List of packages"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:193](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L193) in ``","name":"makeLibraryPath","fn_type":null,"description":["Construct a library search path (such as RPATH) containing the\nlibraries for a set of packages"],"example":"makeLibraryPath [ \"/usr\" \"/usr/local\" ]\n=> \"/usr/lib:/usr/local/lib\"\npkgs = import { }\nmakeLibraryPath [ pkgs.openssl pkgs.zlib ]\n=> \"/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r/lib:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/lib\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:202](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L202) in ``","name":"makeBinPath","fn_type":null,"description":["Construct a binary search path (such as $PATH) containing the\nbinaries for a set of packages."],"example":"makeBinPath [\"/root\" \"/usr\" \"/usr/local\"]\n=> \"/root/bin:/usr/bin:/usr/local/bin\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:212](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L212) in ``","name":"normalizePath","fn_type":"normalizePath :: string -> string","description":["Normalize path, removing extraneous /s"],"example":"normalizePath \"/a//b///c/\"\n=> \"/a/b/c/\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:238](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L238) in ``","name":"optionalString","fn_type":"optionalString :: bool -> string -> string","description":["Depending on the boolean `cond', return either the given string\nor the empty string. Useful to concatenate against a bigger string."],"example":"optionalString true \"some-string\"\n=> \"some-string\"\noptionalString false \"some-string\"\n=> \"\"","args":[{"Flat":{"name":"cond","doc":"Condition"}},{"Flat":{"name":"string","doc":"String to return if condition is true"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:254](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L254) in ``","name":"hasPrefix","fn_type":"hasPrefix :: string -> string -> bool","description":["Determine whether a string has given prefix."],"example":"hasPrefix \"foo\" \"foobar\"\n=> true\nhasPrefix \"foo\" \"barfoo\"\n=> false","args":[{"Flat":{"name":"pref","doc":"Prefix to check for"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:280](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L280) in ``","name":"hasSuffix","fn_type":"hasSuffix :: string -> string -> bool","description":["Determine whether a string has given suffix."],"example":"hasSuffix \"foo\" \"foobar\"\n=> false\nhasSuffix \"foo\" \"barfoo\"\n=> true","args":[{"Flat":{"name":"suffix","doc":"Suffix to check for"}},{"Flat":{"name":"content","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:317](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L317) in ``","name":"hasInfix","fn_type":"hasInfix :: string -> string -> bool","description":["Determine whether a string contains the given infix"],"example":"hasInfix \"bc\" \"abcd\"\n=> true\nhasInfix \"ab\" \"abcd\"\n=> true\nhasInfix \"cd\" \"abcd\"\n=> true\nhasInfix \"foo\" \"abcd\"\n=> false","args":[{"Flat":{"name":"infix","doc":null}},{"Flat":{"name":"content","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:347](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L347) in ``","name":"stringToCharacters","fn_type":"stringToCharacters :: string -> [string]","description":["Convert a string to a list of characters (i.e. singleton strings).\nThis allows you to, e.g., map a function over each character. However,\nnote that this will likely be horribly inefficient; Nix is not a\ngeneral purpose programming language. Complex string manipulations\nshould, if appropriate, be done in a derivation.\nAlso note that Nix treats strings as a list of bytes and thus doesn't\nhandle unicode."],"example":"stringToCharacters \"\"\n=> [ ]\nstringToCharacters \"abc\"\n=> [ \"a\" \"b\" \"c\" ]\nstringToCharacters \"🦄\"\n=> [ \"�\" \"�\" \"�\" \"�\" ]","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:359](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L359) in ``","name":"stringAsChars","fn_type":"stringAsChars :: (string -> string) -> string -> string","description":["Manipulate a string character by character and replace them by\nstrings before concatenating the results."],"example":"stringAsChars (x: if x == \"a\" then \"i\" else x) \"nax\"\n=> \"nix\"","args":[{"Flat":{"name":"f","doc":"Function to map over each individual character"}},{"Flat":{"name":"s","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:378](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L378) in ``","name":"charToInt","fn_type":"charToInt :: string -> int","description":["Convert char to ascii value, must be in printable range"],"example":"charToInt \"A\"\n=> 65\ncharToInt \"(\"\n=> 40","args":[{"Flat":{"name":"c","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:389](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L389) in ``","name":"escape","fn_type":"escape :: [string] -> string -> string","description":["Escape occurrence of the elements of `list` in `string` by\nprefixing it with a backslash."],"example":"escape [\"(\" \")\"] \"(foo)\"\n=> \"\\\\(foo\\\\)\"","args":[{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:402](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L402) in ``","name":"escapeC","fn_type":"escapeC = [string] -> string -> string","description":["Escape occurrence of the element of `list` in `string` by\nconverting to its ASCII value and prefixing it with \\\\x.\nOnly works for printable ascii characters."],"example":"escapeC [\" \"] \"foo bar\"\n=> \"foo\\\\x20bar\"","args":[{"Flat":{"name":"list","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:413](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L413) in ``","name":"escapeURL","fn_type":"escapeURL :: string -> string","description":["Escape the string so it can be safely placed inside a URL\nquery."],"example":"escapeURL \"foo/bar baz\"\n=> \"foo%2Fbar%20baz\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:427](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L427) in ``","name":"escapeShellArg","fn_type":"escapeShellArg :: string -> string","description":["Quote string to be used safely within the Bourne shell."],"example":"escapeShellArg \"esc'ape\\nme\"\n=> \"'esc'\\\\''ape\\nme'\"","args":[{"Flat":{"name":"arg","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:437](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L437) in ``","name":"escapeShellArgs","fn_type":"escapeShellArgs :: [string] -> string","description":["Quote all arguments to be safely passed to the Bourne shell."],"example":"escapeShellArgs [\"one\" \"two three\" \"four'five\"]\n=> \"'one' 'two three' 'four'\\\\''five'\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:449](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L449) in ``","name":"isValidPosixName","fn_type":"string -> bool","description":["Test whether the given name is a valid POSIX shell variable name."],"example":"isValidPosixName \"foo_bar000\"\n=> true\nisValidPosixName \"0-bad.jpg\"\n=> false","args":[{"Flat":{"name":"name","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:469](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L469) in ``","name":"toShellVar","fn_type":"string -> (string | listOf string | attrsOf string) -> string","description":["Translate a Nix value into a shell variable declaration, with proper escaping.","The value can be a string (mapped to a regular variable), a list of strings\n(mapped to a Bash-style array) or an attribute set of strings (mapped to a\nBash-style associative array). Note that \"string\" includes string-coercible\nvalues like paths or derivations.","Strings are translated into POSIX sh-compatible code; lists and attribute sets\nassume a shell that understands Bash syntax (e.g. Bash or ZSH)."],"example":"''\n ${toShellVar \"foo\" \"some string\"}\n [[ \"$foo\" == \"some string\" ]]\n''","args":[{"Flat":{"name":"name","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:497](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L497) in ``","name":"toShellVars","fn_type":"attrsOf (string | listOf string | attrsOf string) -> string","description":["Translate an attribute set into corresponding shell variable declarations\nusing `toShellVar`."],"example":"let\n foo = \"value\";\n bar = foo;\nin ''\n ${toShellVars { inherit foo bar; }}\n [[ \"$foo\" == \"$bar\" ]]\n''","args":[{"Flat":{"name":"vars","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:507](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L507) in ``","name":"escapeNixString","fn_type":"string -> string","description":["Turn a string into a Nix expression representing that string"],"example":"escapeNixString \"hello\\${}\\n\"\n=> \"\\\"hello\\\\\\${}\\\\n\\\"\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:517](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L517) in ``","name":"escapeRegex","fn_type":"string -> string","description":["Turn a string into an exact regular expression"],"example":"escapeRegex \"[^a-z]*\"\n=> \"\\\\[\\\\^a-z]\\\\*\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:529](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L529) in ``","name":"escapeNixIdentifier","fn_type":"string -> string","description":["Quotes a string if it can't be used as an identifier directly."],"example":"escapeNixIdentifier \"hello\"\n=> \"hello\"\nescapeNixIdentifier \"0abc\"\n=> \"\\\"0abc\\\"\"","args":[{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:543](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L543) in ``","name":"escapeXML","fn_type":"string -> string","description":["Escapes a string such that it is safe to include verbatim in an XML\ndocument."],"example":"escapeXML ''\"test\" 'test' < & >''\n=> \""test" 'test' < & >\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:562](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L562) in ``","name":"toLower","fn_type":"toLower :: string -> string","description":["Converts an ASCII string to lower-case."],"example":"toLower \"HOME\"\n=> \"home\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:572](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L572) in ``","name":"toUpper","fn_type":"toUpper :: string -> string","description":["Converts an ASCII string to upper-case."],"example":"toUpper \"home\"\n=> \"HOME\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:587](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L587) in ``","name":"addContextFrom","fn_type":null,"description":["Appends string context from another string. This is an implementation\ndetail of Nix and should be used carefully.","Strings in Nix carry an invisible `context` which is a list of strings\nrepresenting store paths. If the string is later used in a derivation\nattribute, the derivation will properly populate the inputDrvs and\ninputSrcs."],"example":"pkgs = import { };\naddContextFrom pkgs.coreutils \"bar\"\n=> \"bar\"","args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:598](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L598) in ``","name":"splitString","fn_type":null,"description":["Cut a string with a separator and produces a list of strings which\nwere separated by this separator."],"example":"splitString \".\" \"foo.bar.baz\"\n=> [ \"foo\" \"bar\" \"baz\" ]\nsplitString \"/\" \"/usr/local/bin\"\n=> [ \"\" \"usr\" \"local\" \"bin\" ]","args":[{"Flat":{"name":"sep","doc":null}},{"Flat":{"name":"s","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:614](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L614) in ``","name":"removePrefix","fn_type":"string -> string -> string","description":["Return a string without the specified prefix, if the prefix matches."],"example":"removePrefix \"foo.\" \"foo.bar.baz\"\n=> \"bar.baz\"\nremovePrefix \"xxx\" \"foo.bar.baz\"\n=> \"foo.bar.baz\"","args":[{"Flat":{"name":"prefix","doc":"Prefix to remove if it matches"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:647](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L647) in ``","name":"removeSuffix","fn_type":"string -> string -> string","description":["Return a string without the specified suffix, if the suffix matches."],"example":"removeSuffix \"front\" \"homefront\"\n=> \"home\"\nremoveSuffix \"xxx\" \"homefront\"\n=> \"homefront\"","args":[{"Flat":{"name":"suffix","doc":"Suffix to remove if it matches"}},{"Flat":{"name":"str","doc":"Input string"}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:678](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L678) in ``","name":"versionOlder","fn_type":null,"description":["Return true if string v1 denotes a version older than v2."],"example":"versionOlder \"1.1\" \"1.2\"\n=> true\nversionOlder \"1.1\" \"1.1\"\n=> false","args":[{"Flat":{"name":"v1","doc":null}},{"Flat":{"name":"v2","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:690](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L690) in ``","name":"versionAtLeast","fn_type":null,"description":["Return true if string v1 denotes a version equal to or newer than v2."],"example":"versionAtLeast \"1.1\" \"1.0\"\n=> true\nversionAtLeast \"1.1\" \"1.1\"\n=> true\nversionAtLeast \"1.1\" \"1.2\"\n=> false","args":[{"Flat":{"name":"v1","doc":null}},{"Flat":{"name":"v2","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:702](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L702) in ``","name":"getName","fn_type":null,"description":["This function takes an argument that's either a derivation or a\nderivation's \"name\" attribute and extracts the name part from that\nargument."],"example":"getName \"youtube-dl-2016.01.01\"\n=> \"youtube-dl\"\ngetName pkgs.youtube-dl\n=> \"youtube-dl\"","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:719](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L719) in ``","name":"getVersion","fn_type":null,"description":["This function takes an argument that's either a derivation or a\nderivation's \"name\" attribute and extracts the version part from that\nargument."],"example":"getVersion \"youtube-dl-2016.01.01\"\n=> \"2016.01.01\"\ngetVersion pkgs.youtube-dl\n=> \"2016.01.01\"","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:735](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L735) in ``","name":"nameFromURL","fn_type":null,"description":["Extract name with version from URL. Ask for separator which is\nsupposed to start extension."],"example":"nameFromURL \"https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2\" \"-\"\n=> \"nix\"\nnameFromURL \"https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2\" \"_\"\n=> \"nix-1.7-x86\"","args":[{"Flat":{"name":"url","doc":null}},{"Flat":{"name":"sep","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:754](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L754) in ``","name":"mesonOption","fn_type":"mesonOption :: string -> string -> string\n\n@param feature The feature to be set\n@param value The desired value","description":["Create a -D= string that can be passed to typical Meson\ninvocations."],"example":"mesonOption \"engine\" \"opengl\"\n=> \"-Dengine=opengl\"","args":[{"Flat":{"name":"feature","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:773](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L773) in ``","name":"mesonBool","fn_type":"mesonBool :: string -> bool -> string\n\n@param condition The condition to be made true or false\n@param flag The controlling flag of the condition","description":["Create a -D={true,false} string that can be passed to typical\nMeson invocations."],"example":"mesonBool \"hardened\" true\n=> \"-Dhardened=true\"\nmesonBool \"static\" false\n=> \"-Dstatic=false\"","args":[{"Flat":{"name":"condition","doc":null}},{"Flat":{"name":"flag","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:792](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L792) in ``","name":"mesonEnable","fn_type":"mesonEnable :: string -> bool -> string\n\n@param feature The feature to be enabled or disabled\n@param flag The controlling flag","description":["Create a -D={enabled,disabled} string that can be passed to\ntypical Meson invocations."],"example":"mesonEnable \"docs\" true\n=> \"-Ddocs=enabled\"\nmesonEnable \"savage\" false\n=> \"-Dsavage=disabled\"","args":[{"Flat":{"name":"feature","doc":null}},{"Flat":{"name":"flag","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:806](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L806) in ``","name":"enableFeature","fn_type":null,"description":["Create an --{enable,disable}- string that can be passed to\nstandard GNU Autoconf scripts."],"example":"enableFeature true \"shared\"\n=> \"--enable-shared\"\nenableFeature false \"shared\"\n=> \"--disable-shared\"","args":[{"Flat":{"name":"enable","doc":null}},{"Flat":{"name":"feat","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:819](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L819) in ``","name":"enableFeatureAs","fn_type":null,"description":["Create an --{enable-=,disable-} string that can be passed to\nstandard GNU Autoconf scripts."],"example":"enableFeatureAs true \"shared\" \"foo\"\n=> \"--enable-shared=foo\"\nenableFeatureAs false \"shared\" (throw \"ignored\")\n=> \"--disable-shared\"","args":[{"Flat":{"name":"enable","doc":null}},{"Flat":{"name":"feat","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:830](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L830) in ``","name":"withFeature","fn_type":null,"description":["Create an --{with,without}- string that can be passed to\nstandard GNU Autoconf scripts."],"example":"withFeature true \"shared\"\n=> \"--with-shared\"\nwithFeature false \"shared\"\n=> \"--without-shared\"","args":[{"Flat":{"name":"with_","doc":null}},{"Flat":{"name":"feat","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:843](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L843) in ``","name":"withFeatureAs","fn_type":null,"description":["Create an --{with-=,without-} string that can be passed to\nstandard GNU Autoconf scripts."],"example":"withFeatureAs true \"shared\" \"foo\"\n=> \"--with-shared=foo\"\nwithFeatureAs false \"shared\" (throw \"ignored\")\n=> \"--without-shared\"","args":[{"Flat":{"name":"with_","doc":null}},{"Flat":{"name":"feat","doc":null}},{"Flat":{"name":"value","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:857](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L857) in ``","name":"fixedWidthString","fn_type":"fixedWidthString :: int -> string -> string -> string","description":["Create a fixed width string with additional prefix to match\nrequired width.","This function will fail if the input string is longer than the\nrequested length."],"example":"fixedWidthString 5 \"0\" (toString 15)\n=> \"00015\"","args":[{"Flat":{"name":"width","doc":null}},{"Flat":{"name":"filler","doc":null}},{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:874](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L874) in ``","name":"fixedWidthNumber","fn_type":null,"description":["Format a number adding leading zeroes up to fixed width."],"example":"fixedWidthNumber 5 15\n=> \"00015\"","args":[{"Flat":{"name":"width","doc":null}},{"Flat":{"name":"n","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:886](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L886) in ``","name":"floatToString","fn_type":null,"description":["Convert a float to a string, but emit a warning when precision is lost\nduring the conversion"],"example":"floatToString 0.000001\n=> \"0.000001\"\nfloatToString 0.0000001\n=> trace: warning: Imprecise conversion from float to string 0.000000\n \"0.000000\"","args":[{"Flat":{"name":"float","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:894](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L894) in ``","name":"isCoercibleToString","fn_type":null,"description":["Soft-deprecated function. While the original implementation is available as\nisConvertibleWithToString, consider using isStringLike instead, if suitable."],"example":null,"args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:903](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L903) in ``","name":"isConvertibleWithToString","fn_type":null,"description":["Check whether a list or other value can be passed to toString.","Many types of value are coercible to string this way, including int, float,\nnull, bool, list of similarly coercible values."],"example":null,"args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:914](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L914) in ``","name":"isStringLike","fn_type":null,"description":["Check whether a value can be coerced to a string.\nThe value must be a string, path, or attribute set.","String-like values can be used without explicit conversion in\nstring interpolations and in most functions that expect a string."],"example":null,"args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:932](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L932) in ``","name":"isStorePath","fn_type":null,"description":["Check whether a value is a store path."],"example":"isStorePath \"/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11/bin/python\"\n=> false\nisStorePath \"/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11\"\n=> true\nisStorePath pkgs.python\n=> true\nisStorePath [] || isStorePath 42 || isStorePath {} || …\n=> false","args":[{"Flat":{"name":"x","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:962](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L962) in ``","name":"toInt","fn_type":"string -> int","description":["Parse a string as an int. Does not support parsing of integers with preceding zero due to\nambiguity between zero-padded and octal numbers. See toIntBase10."],"example":"toInt \"1337\"\n=> 1337\n\ntoInt \"-4\"\n=> -4\n\ntoInt \" 123 \"\n=> 123\n\ntoInt \"00024\"\n=> error: Ambiguity in interpretation of 00024 between octal and zero padded integer.\n\ntoInt \"3.14\"\n=> error: floating point JSON numbers are not supported","args":[{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1013](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1013) in ``","name":"toIntBase10","fn_type":"string -> int","description":["Parse a string as a base 10 int. This supports parsing of zero-padded integers."],"example":"toIntBase10 \"1337\"\n=> 1337\n\ntoIntBase10 \"-4\"\n=> -4\n\ntoIntBase10 \" 123 \"\n=> 123\n\ntoIntBase10 \"00024\"\n=> 24\n\ntoIntBase10 \"3.14\"\n=> error: floating point JSON numbers are not supported","args":[{"Flat":{"name":"str","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1056](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1056) in ``","name":"readPathsFromFile","fn_type":null,"description":["Read a list of paths from `file`, relative to the `rootPath`.\nLines beginning with `#` are treated as comments and ignored.\nWhitespace is significant.","NOTE: This function is not performant and should be avoided."],"example":"readPathsFromFile /prefix\n ./pkgs/development/libraries/qt-5/5.4/qtbase/series\n=> [ \"/prefix/dlopen-resolv.patch\" \"/prefix/tzdir.patch\"\n \"/prefix/dlopen-libXcursor.patch\" \"/prefix/dlopen-openssl.patch\"\n \"/prefix/dlopen-dbus.patch\" \"/prefix/xdg-config-dirs.patch\"\n \"/prefix/nix-profiles-library-paths.patch\"\n \"/prefix/compose-search-path.patch\" ]","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1076](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1076) in ``","name":"fileContents","fn_type":"fileContents :: path -> string","description":["Read the contents of a file removing the trailing \\n"],"example":"$ echo \"1.0\" > ./version\n\nfileContents ./version\n=> \"1.0\"","args":[{"Flat":{"name":"file","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1091](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1091) in ``","name":"sanitizeDerivationName","fn_type":"sanitizeDerivationName :: String -> String","description":["Creates a valid derivation name from a potentially invalid one."],"example":"sanitizeDerivationName \"../hello.bar # foo\"\n=> \"-hello.bar-foo\"\nsanitizeDerivationName \"\"\n=> \"unknown\"\nsanitizeDerivationName pkgs.hello\n=> \"-nix-store-2g75chlbpxlrqn15zlby2dfh8hr9qwbk-hello-2.10\"","args":[]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1130](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1130) in ``","name":"levenshtein","fn_type":"levenshtein :: string -> string -> int","description":["Computes the Levenshtein distance between two strings.\nComplexity O(n*m) where n and m are the lengths of the strings.\nAlgorithm adjusted from https://stackoverflow.com/a/9750974/6605742"],"example":"levenshtein \"foo\" \"foo\"\n=> 0\nlevenshtein \"book\" \"hook\"\n=> 1\nlevenshtein \"hello\" \"Heyo\"\n=> 3","args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1151](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1151) in ``","name":"commonPrefixLength","fn_type":null,"description":["Returns the length of the prefix common to both strings."],"example":null,"args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1159](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1159) in ``","name":"commonSuffixLength","fn_type":null,"description":["Returns the length of the suffix common to both strings."],"example":null,"args":[{"Flat":{"name":"a","doc":null}},{"Flat":{"name":"b","doc":null}}]},{"prefix":"lib","category":"strings","location":"[lib/strings.nix:1183](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1183) in ``","name":"levenshteinAtMost","fn_type":"levenshteinAtMost :: int -> string -> string -> bool","description":["Returns whether the levenshtein distance between two strings is at most some value\nComplexity is O(min(n,m)) for k <= 2 and O(n*m) otherwise"],"example":"levenshteinAtMost 0 \"foo\" \"foo\"\n=> true\nlevenshteinAtMost 1 \"foo\" \"boa\"\n=> false\nlevenshteinAtMost 2 \"foo\" \"boa\"\n=> true\nlevenshteinAtMost 2 \"This is a sentence\" \"this is a sentense.\"\n=> false\nlevenshteinAtMost 3 \"This is a sentence\" \"this is a sentense.\"\n=> true","args":[]}]} 7 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__line_comments.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/main.rs 3 | expression: output 4 | --- 5 | ## `lib.let.shown` {#function-library-lib.let.shown} 6 | 7 | is a doc comment 8 | 9 | `a` 10 | 11 | : a doc comment 12 | 13 | 14 | `b` 15 | 16 | : also a doc comment 17 | 18 | 19 | `c` 20 | 21 | : a doc comment with continuation 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__main_minimal.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | ## `concatStrings` {#concatStrings} 6 | 7 | **Type**: `concatStrings :: [string] -> string` 8 | 9 | Concatenate a list of strings. 10 | 11 | ::: {.example #example-concatStrings} 12 | # `concatStrings` usage example 13 | 14 | ```nix 15 | concatStrings ["foo" "bar"] 16 | => "foobar" 17 | ``` 18 | ::: 19 | 20 | ## `concatMapStrings` {#concatMapStrings} 21 | 22 | **Type**: `concatMapStrings :: (a -> string) -> [a] -> string` 23 | 24 | Map a function over a list and concatenate the resulting strings. 25 | 26 | `f` 27 | 28 | : Function argument 29 | 30 | 31 | `list` 32 | 33 | : Function argument 34 | 35 | 36 | ::: {.example #example-concatMapStrings} 37 | # `concatMapStrings` usage example 38 | 39 | ```nix 40 | concatMapStrings (x: "a" + x) ["foo" "bar"] 41 | => "afooabar" 42 | ``` 43 | ::: 44 | 45 | ## `concatImapStrings` {#concatImapStrings} 46 | 47 | **Type**: `concatImapStrings :: (int -> a -> string) -> [a] -> string` 48 | 49 | Like `concatMapStrings` except that the f functions also gets the 50 | position as a parameter. 51 | 52 | `f` 53 | 54 | : Function argument 55 | 56 | 57 | `list` 58 | 59 | : Function argument 60 | 61 | 62 | ::: {.example #example-concatImapStrings} 63 | # `concatImapStrings` usage example 64 | 65 | ```nix 66 | concatImapStrings (pos: x: "${toString pos}-${x}") ["foo" "bar"] 67 | => "1-foo2-bar" 68 | ``` 69 | ::: 70 | 71 | ## `intersperse` {#intersperse} 72 | 73 | **Type**: `intersperse :: a -> [a] -> [a]` 74 | 75 | Place an element between each element of a list 76 | 77 | `separator` 78 | 79 | : Separator to add between elements 80 | 81 | 82 | `list` 83 | 84 | : Input list 85 | 86 | 87 | ::: {.example #example-intersperse} 88 | # `intersperse` usage example 89 | 90 | ```nix 91 | intersperse "/" ["usr" "local" "bin"] 92 | => ["usr" "/" "local" "/" "bin"]. 93 | ``` 94 | ::: 95 | 96 | ## `concatStringsSep` {#concatStringsSep} 97 | 98 | **Type**: `concatStringsSep :: string -> [string] -> string` 99 | 100 | Concatenate a list of strings with a separator between each element 101 | 102 | ::: {.example #example-concatStringsSep} 103 | # `concatStringsSep` usage example 104 | 105 | ```nix 106 | concatStringsSep "/" ["usr" "local" "bin"] 107 | => "usr/local/bin" 108 | ``` 109 | ::: 110 | 111 | ## `concatMapStringsSep` {#concatMapStringsSep} 112 | 113 | **Type**: `concatMapStringsSep :: string -> (a -> string) -> [a] -> string` 114 | 115 | Maps a function over a list of strings and then concatenates the 116 | result with the specified separator interspersed between 117 | elements. 118 | 119 | `sep` 120 | 121 | : Separator to add between elements 122 | 123 | 124 | `f` 125 | 126 | : Function to map over the list 127 | 128 | 129 | `list` 130 | 131 | : List of input strings 132 | 133 | 134 | ::: {.example #example-concatMapStringsSep} 135 | # `concatMapStringsSep` usage example 136 | 137 | ```nix 138 | concatMapStringsSep "-" (x: toUpper x) ["foo" "bar" "baz"] 139 | => "FOO-BAR-BAZ" 140 | ``` 141 | ::: 142 | 143 | ## `concatImapStringsSep` {#concatImapStringsSep} 144 | 145 | **Type**: `concatIMapStringsSep :: string -> (int -> a -> string) -> [a] -> string` 146 | 147 | Same as `concatMapStringsSep`, but the mapping function 148 | additionally receives the position of its argument. 149 | 150 | `sep` 151 | 152 | : Separator to add between elements 153 | 154 | 155 | `f` 156 | 157 | : Function that receives elements and their positions 158 | 159 | 160 | `list` 161 | 162 | : List of input strings 163 | 164 | 165 | ::: {.example #example-concatImapStringsSep} 166 | # `concatImapStringsSep` usage example 167 | 168 | ```nix 169 | concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ] 170 | => "6-3-2" 171 | ``` 172 | ::: 173 | 174 | ## `concatLines` {#concatLines} 175 | 176 | **Type**: `concatLines :: [string] -> string` 177 | 178 | Concatenate a list of strings, adding a newline at the end of each one. 179 | Defined as `concatMapStrings (s: s + "\n")`. 180 | 181 | ::: {.example #example-concatLines} 182 | # `concatLines` usage example 183 | 184 | ```nix 185 | concatLines [ "foo" "bar" ] 186 | => "foo\nbar\n" 187 | ``` 188 | ::: 189 | 190 | ## `makeSearchPath` {#makeSearchPath} 191 | 192 | **Type**: `makeSearchPath :: string -> [string] -> string` 193 | 194 | Construct a Unix-style, colon-separated search path consisting of 195 | the given `subDir` appended to each of the given paths. 196 | 197 | `subDir` 198 | 199 | : Directory name to append 200 | 201 | 202 | `paths` 203 | 204 | : List of base paths 205 | 206 | 207 | ::: {.example #example-makeSearchPath} 208 | # `makeSearchPath` usage example 209 | 210 | ```nix 211 | makeSearchPath "bin" ["/root" "/usr" "/usr/local"] 212 | => "/root/bin:/usr/bin:/usr/local/bin" 213 | makeSearchPath "bin" [""] 214 | => "/bin" 215 | ``` 216 | ::: 217 | 218 | ## `makeSearchPathOutput` {#makeSearchPathOutput} 219 | 220 | **Type**: `string -> string -> [package] -> string` 221 | 222 | Construct a Unix-style search path by appending the given 223 | `subDir` to the specified `output` of each of the packages. If no 224 | output by the given name is found, fallback to `.out` and then to 225 | the default. 226 | 227 | `output` 228 | 229 | : Package output to use 230 | 231 | 232 | `subDir` 233 | 234 | : Directory name to append 235 | 236 | 237 | `pkgs` 238 | 239 | : List of packages 240 | 241 | 242 | ::: {.example #example-makeSearchPathOutput} 243 | # `makeSearchPathOutput` usage example 244 | 245 | ```nix 246 | makeSearchPathOutput "dev" "bin" [ pkgs.openssl pkgs.zlib ] 247 | => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev/bin:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/bin" 248 | ``` 249 | ::: 250 | 251 | ## `makeLibraryPath` {#makeLibraryPath} 252 | 253 | Construct a library search path (such as RPATH) containing the 254 | libraries for a set of packages 255 | 256 | ::: {.example #example-makeLibraryPath} 257 | # `makeLibraryPath` usage example 258 | 259 | ```nix 260 | makeLibraryPath [ "/usr" "/usr/local" ] 261 | => "/usr/lib:/usr/local/lib" 262 | pkgs = import { } 263 | makeLibraryPath [ pkgs.openssl pkgs.zlib ] 264 | => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r/lib:/nix/store/wwh7mhwh269sfjkm6k5665b5kgp7jrk2-zlib-1.2.8/lib" 265 | ``` 266 | ::: 267 | 268 | ## `makeBinPath` {#makeBinPath} 269 | 270 | Construct a binary search path (such as $PATH) containing the 271 | binaries for a set of packages. 272 | 273 | ::: {.example #example-makeBinPath} 274 | # `makeBinPath` usage example 275 | 276 | ```nix 277 | makeBinPath ["/root" "/usr" "/usr/local"] 278 | => "/root/bin:/usr/bin:/usr/local/bin" 279 | ``` 280 | ::: 281 | 282 | ## `normalizePath` {#normalizePath} 283 | 284 | **Type**: `normalizePath :: string -> string` 285 | 286 | Normalize path, removing extraneous /s 287 | 288 | `s` 289 | 290 | : Function argument 291 | 292 | 293 | ::: {.example #example-normalizePath} 294 | # `normalizePath` usage example 295 | 296 | ```nix 297 | normalizePath "/a//b///c/" 298 | => "/a/b/c/" 299 | ``` 300 | ::: 301 | 302 | ## `optionalString` {#optionalString} 303 | 304 | **Type**: `optionalString :: bool -> string -> string` 305 | 306 | Depending on the boolean `cond', return either the given string 307 | or the empty string. Useful to concatenate against a bigger string. 308 | 309 | `cond` 310 | 311 | : Condition 312 | 313 | 314 | `string` 315 | 316 | : String to return if condition is true 317 | 318 | 319 | ::: {.example #example-optionalString} 320 | # `optionalString` usage example 321 | 322 | ```nix 323 | optionalString true "some-string" 324 | => "some-string" 325 | optionalString false "some-string" 326 | => "" 327 | ``` 328 | ::: 329 | 330 | ## `hasPrefix` {#hasPrefix} 331 | 332 | **Type**: `hasPrefix :: string -> string -> bool` 333 | 334 | Determine whether a string has given prefix. 335 | 336 | `pref` 337 | 338 | : Prefix to check for 339 | 340 | 341 | `str` 342 | 343 | : Input string 344 | 345 | 346 | ::: {.example #example-hasPrefix} 347 | # `hasPrefix` usage example 348 | 349 | ```nix 350 | hasPrefix "foo" "foobar" 351 | => true 352 | hasPrefix "foo" "barfoo" 353 | => false 354 | ``` 355 | ::: 356 | 357 | ## `hasSuffix` {#hasSuffix} 358 | 359 | **Type**: `hasSuffix :: string -> string -> bool` 360 | 361 | Determine whether a string has given suffix. 362 | 363 | `suffix` 364 | 365 | : Suffix to check for 366 | 367 | 368 | `content` 369 | 370 | : Input string 371 | 372 | 373 | ::: {.example #example-hasSuffix} 374 | # `hasSuffix` usage example 375 | 376 | ```nix 377 | hasSuffix "foo" "foobar" 378 | => false 379 | hasSuffix "foo" "barfoo" 380 | => true 381 | ``` 382 | ::: 383 | 384 | ## `hasInfix` {#hasInfix} 385 | 386 | **Type**: `hasInfix :: string -> string -> bool` 387 | 388 | Determine whether a string contains the given infix 389 | 390 | `infix` 391 | 392 | : Function argument 393 | 394 | 395 | `content` 396 | 397 | : Function argument 398 | 399 | 400 | ::: {.example #example-hasInfix} 401 | # `hasInfix` usage example 402 | 403 | ```nix 404 | hasInfix "bc" "abcd" 405 | => true 406 | hasInfix "ab" "abcd" 407 | => true 408 | hasInfix "cd" "abcd" 409 | => true 410 | hasInfix "foo" "abcd" 411 | => false 412 | ``` 413 | ::: 414 | 415 | ## `stringToCharacters` {#stringToCharacters} 416 | 417 | **Type**: `stringToCharacters :: string -> [string]` 418 | 419 | Convert a string to a list of characters (i.e. singleton strings). 420 | This allows you to, e.g., map a function over each character. However, 421 | note that this will likely be horribly inefficient; Nix is not a 422 | general purpose programming language. Complex string manipulations 423 | should, if appropriate, be done in a derivation. 424 | Also note that Nix treats strings as a list of bytes and thus doesn't 425 | handle unicode. 426 | 427 | `s` 428 | 429 | : Function argument 430 | 431 | 432 | ::: {.example #example-stringToCharacters} 433 | # `stringToCharacters` usage example 434 | 435 | ```nix 436 | stringToCharacters "" 437 | => [ ] 438 | stringToCharacters "abc" 439 | => [ "a" "b" "c" ] 440 | stringToCharacters "🦄" 441 | => [ "�" "�" "�" "�" ] 442 | ``` 443 | ::: 444 | 445 | ## `stringAsChars` {#stringAsChars} 446 | 447 | **Type**: `stringAsChars :: (string -> string) -> string -> string` 448 | 449 | Manipulate a string character by character and replace them by 450 | strings before concatenating the results. 451 | 452 | `f` 453 | 454 | : Function to map over each individual character 455 | 456 | 457 | `s` 458 | 459 | : Input string 460 | 461 | 462 | ::: {.example #example-stringAsChars} 463 | # `stringAsChars` usage example 464 | 465 | ```nix 466 | stringAsChars (x: if x == "a" then "i" else x) "nax" 467 | => "nix" 468 | ``` 469 | ::: 470 | 471 | ## `charToInt` {#charToInt} 472 | 473 | **Type**: `charToInt :: string -> int` 474 | 475 | Convert char to ascii value, must be in printable range 476 | 477 | `c` 478 | 479 | : Function argument 480 | 481 | 482 | ::: {.example #example-charToInt} 483 | # `charToInt` usage example 484 | 485 | ```nix 486 | charToInt "A" 487 | => 65 488 | charToInt "(" 489 | => 40 490 | ``` 491 | ::: 492 | 493 | ## `escape` {#escape} 494 | 495 | **Type**: `escape :: [string] -> string -> string` 496 | 497 | Escape occurrence of the elements of `list` in `string` by 498 | prefixing it with a backslash. 499 | 500 | `list` 501 | 502 | : Function argument 503 | 504 | 505 | ::: {.example #example-escape} 506 | # `escape` usage example 507 | 508 | ```nix 509 | escape ["(" ")"] "(foo)" 510 | => "\\(foo\\)" 511 | ``` 512 | ::: 513 | 514 | ## `escapeC` {#escapeC} 515 | 516 | **Type**: `escapeC = [string] -> string -> string` 517 | 518 | Escape occurrence of the element of `list` in `string` by 519 | converting to its ASCII value and prefixing it with \\x. 520 | Only works for printable ascii characters. 521 | 522 | `list` 523 | 524 | : Function argument 525 | 526 | 527 | ::: {.example #example-escapeC} 528 | # `escapeC` usage example 529 | 530 | ```nix 531 | escapeC [" "] "foo bar" 532 | => "foo\\x20bar" 533 | ``` 534 | ::: 535 | 536 | ## `escapeURL` {#escapeURL} 537 | 538 | **Type**: `escapeURL :: string -> string` 539 | 540 | Escape the string so it can be safely placed inside a URL 541 | query. 542 | 543 | ::: {.example #example-escapeURL} 544 | # `escapeURL` usage example 545 | 546 | ```nix 547 | escapeURL "foo/bar baz" 548 | => "foo%2Fbar%20baz" 549 | ``` 550 | ::: 551 | 552 | ## `escapeShellArg` {#escapeShellArg} 553 | 554 | **Type**: `escapeShellArg :: string -> string` 555 | 556 | Quote string to be used safely within the Bourne shell. 557 | 558 | `arg` 559 | 560 | : Function argument 561 | 562 | 563 | ::: {.example #example-escapeShellArg} 564 | # `escapeShellArg` usage example 565 | 566 | ```nix 567 | escapeShellArg "esc'ape\nme" 568 | => "'esc'\\''ape\nme'" 569 | ``` 570 | ::: 571 | 572 | ## `escapeShellArgs` {#escapeShellArgs} 573 | 574 | **Type**: `escapeShellArgs :: [string] -> string` 575 | 576 | Quote all arguments to be safely passed to the Bourne shell. 577 | 578 | ::: {.example #example-escapeShellArgs} 579 | # `escapeShellArgs` usage example 580 | 581 | ```nix 582 | escapeShellArgs ["one" "two three" "four'five"] 583 | => "'one' 'two three' 'four'\\''five'" 584 | ``` 585 | ::: 586 | 587 | ## `isValidPosixName` {#isValidPosixName} 588 | 589 | **Type**: `string -> bool` 590 | 591 | Test whether the given name is a valid POSIX shell variable name. 592 | 593 | `name` 594 | 595 | : Function argument 596 | 597 | 598 | ::: {.example #example-isValidPosixName} 599 | # `isValidPosixName` usage example 600 | 601 | ```nix 602 | isValidPosixName "foo_bar000" 603 | => true 604 | isValidPosixName "0-bad.jpg" 605 | => false 606 | ``` 607 | ::: 608 | 609 | ## `toShellVar` {#toShellVar} 610 | 611 | **Type**: `string -> (string | listOf string | attrsOf string) -> string` 612 | 613 | Translate a Nix value into a shell variable declaration, with proper escaping. 614 | 615 | The value can be a string (mapped to a regular variable), a list of strings 616 | (mapped to a Bash-style array) or an attribute set of strings (mapped to a 617 | Bash-style associative array). Note that "string" includes string-coercible 618 | values like paths or derivations. 619 | 620 | Strings are translated into POSIX sh-compatible code; lists and attribute sets 621 | assume a shell that understands Bash syntax (e.g. Bash or ZSH). 622 | 623 | `name` 624 | 625 | : Function argument 626 | 627 | 628 | `value` 629 | 630 | : Function argument 631 | 632 | 633 | ::: {.example #example-toShellVar} 634 | # `toShellVar` usage example 635 | 636 | ```nix 637 | '' 638 | ${toShellVar "foo" "some string"} 639 | [[ "$foo" == "some string" ]] 640 | '' 641 | ``` 642 | ::: 643 | 644 | ## `toShellVars` {#toShellVars} 645 | 646 | **Type**: `attrsOf (string | listOf string | attrsOf string) -> string` 647 | 648 | Translate an attribute set into corresponding shell variable declarations 649 | using `toShellVar`. 650 | 651 | `vars` 652 | 653 | : Function argument 654 | 655 | 656 | ::: {.example #example-toShellVars} 657 | # `toShellVars` usage example 658 | 659 | ```nix 660 | let 661 | foo = "value"; 662 | bar = foo; 663 | in '' 664 | ${toShellVars { inherit foo bar; }} 665 | [[ "$foo" == "$bar" ]] 666 | '' 667 | ``` 668 | ::: 669 | 670 | ## `escapeNixString` {#escapeNixString} 671 | 672 | **Type**: `string -> string` 673 | 674 | Turn a string into a Nix expression representing that string 675 | 676 | `s` 677 | 678 | : Function argument 679 | 680 | 681 | ::: {.example #example-escapeNixString} 682 | # `escapeNixString` usage example 683 | 684 | ```nix 685 | escapeNixString "hello\${}\n" 686 | => "\"hello\\\${}\\n\"" 687 | ``` 688 | ::: 689 | 690 | ## `escapeRegex` {#escapeRegex} 691 | 692 | **Type**: `string -> string` 693 | 694 | Turn a string into an exact regular expression 695 | 696 | ::: {.example #example-escapeRegex} 697 | # `escapeRegex` usage example 698 | 699 | ```nix 700 | escapeRegex "[^a-z]*" 701 | => "\\[\\^a-z]\\*" 702 | ``` 703 | ::: 704 | 705 | ## `escapeNixIdentifier` {#escapeNixIdentifier} 706 | 707 | **Type**: `string -> string` 708 | 709 | Quotes a string if it can't be used as an identifier directly. 710 | 711 | `s` 712 | 713 | : Function argument 714 | 715 | 716 | ::: {.example #example-escapeNixIdentifier} 717 | # `escapeNixIdentifier` usage example 718 | 719 | ```nix 720 | escapeNixIdentifier "hello" 721 | => "hello" 722 | escapeNixIdentifier "0abc" 723 | => "\"0abc\"" 724 | ``` 725 | ::: 726 | 727 | ## `escapeXML` {#escapeXML} 728 | 729 | **Type**: `string -> string` 730 | 731 | Escapes a string such that it is safe to include verbatim in an XML 732 | document. 733 | 734 | ::: {.example #example-escapeXML} 735 | # `escapeXML` usage example 736 | 737 | ```nix 738 | escapeXML ''"test" 'test' < & >'' 739 | => ""test" 'test' < & >" 740 | ``` 741 | ::: 742 | 743 | ## `toLower` {#toLower} 744 | 745 | **Type**: `toLower :: string -> string` 746 | 747 | Converts an ASCII string to lower-case. 748 | 749 | ::: {.example #example-toLower} 750 | # `toLower` usage example 751 | 752 | ```nix 753 | toLower "HOME" 754 | => "home" 755 | ``` 756 | ::: 757 | 758 | ## `toUpper` {#toUpper} 759 | 760 | **Type**: `toUpper :: string -> string` 761 | 762 | Converts an ASCII string to upper-case. 763 | 764 | ::: {.example #example-toUpper} 765 | # `toUpper` usage example 766 | 767 | ```nix 768 | toUpper "home" 769 | => "HOME" 770 | ``` 771 | ::: 772 | 773 | ## `addContextFrom` {#addContextFrom} 774 | 775 | Appends string context from another string. This is an implementation 776 | detail of Nix and should be used carefully. 777 | 778 | Strings in Nix carry an invisible `context` which is a list of strings 779 | representing store paths. If the string is later used in a derivation 780 | attribute, the derivation will properly populate the inputDrvs and 781 | inputSrcs. 782 | 783 | `a` 784 | 785 | : Function argument 786 | 787 | 788 | `b` 789 | 790 | : Function argument 791 | 792 | 793 | ::: {.example #example-addContextFrom} 794 | # `addContextFrom` usage example 795 | 796 | ```nix 797 | pkgs = import { }; 798 | addContextFrom pkgs.coreutils "bar" 799 | => "bar" 800 | ``` 801 | ::: 802 | 803 | ## `splitString` {#splitString} 804 | 805 | Cut a string with a separator and produces a list of strings which 806 | were separated by this separator. 807 | 808 | `sep` 809 | 810 | : Function argument 811 | 812 | 813 | `s` 814 | 815 | : Function argument 816 | 817 | 818 | ::: {.example #example-splitString} 819 | # `splitString` usage example 820 | 821 | ```nix 822 | splitString "." "foo.bar.baz" 823 | => [ "foo" "bar" "baz" ] 824 | splitString "/" "/usr/local/bin" 825 | => [ "" "usr" "local" "bin" ] 826 | ``` 827 | ::: 828 | 829 | ## `removePrefix` {#removePrefix} 830 | 831 | **Type**: `string -> string -> string` 832 | 833 | Return a string without the specified prefix, if the prefix matches. 834 | 835 | `prefix` 836 | 837 | : Prefix to remove if it matches 838 | 839 | 840 | `str` 841 | 842 | : Input string 843 | 844 | 845 | ::: {.example #example-removePrefix} 846 | # `removePrefix` usage example 847 | 848 | ```nix 849 | removePrefix "foo." "foo.bar.baz" 850 | => "bar.baz" 851 | removePrefix "xxx" "foo.bar.baz" 852 | => "foo.bar.baz" 853 | ``` 854 | ::: 855 | 856 | ## `removeSuffix` {#removeSuffix} 857 | 858 | **Type**: `string -> string -> string` 859 | 860 | Return a string without the specified suffix, if the suffix matches. 861 | 862 | `suffix` 863 | 864 | : Suffix to remove if it matches 865 | 866 | 867 | `str` 868 | 869 | : Input string 870 | 871 | 872 | ::: {.example #example-removeSuffix} 873 | # `removeSuffix` usage example 874 | 875 | ```nix 876 | removeSuffix "front" "homefront" 877 | => "home" 878 | removeSuffix "xxx" "homefront" 879 | => "homefront" 880 | ``` 881 | ::: 882 | 883 | ## `versionOlder` {#versionOlder} 884 | 885 | Return true if string v1 denotes a version older than v2. 886 | 887 | `v1` 888 | 889 | : Function argument 890 | 891 | 892 | `v2` 893 | 894 | : Function argument 895 | 896 | 897 | ::: {.example #example-versionOlder} 898 | # `versionOlder` usage example 899 | 900 | ```nix 901 | versionOlder "1.1" "1.2" 902 | => true 903 | versionOlder "1.1" "1.1" 904 | => false 905 | ``` 906 | ::: 907 | 908 | ## `versionAtLeast` {#versionAtLeast} 909 | 910 | Return true if string v1 denotes a version equal to or newer than v2. 911 | 912 | `v1` 913 | 914 | : Function argument 915 | 916 | 917 | `v2` 918 | 919 | : Function argument 920 | 921 | 922 | ::: {.example #example-versionAtLeast} 923 | # `versionAtLeast` usage example 924 | 925 | ```nix 926 | versionAtLeast "1.1" "1.0" 927 | => true 928 | versionAtLeast "1.1" "1.1" 929 | => true 930 | versionAtLeast "1.1" "1.2" 931 | => false 932 | ``` 933 | ::: 934 | 935 | ## `getName` {#getName} 936 | 937 | This function takes an argument that's either a derivation or a 938 | derivation's "name" attribute and extracts the name part from that 939 | argument. 940 | 941 | `x` 942 | 943 | : Function argument 944 | 945 | 946 | ::: {.example #example-getName} 947 | # `getName` usage example 948 | 949 | ```nix 950 | getName "youtube-dl-2016.01.01" 951 | => "youtube-dl" 952 | getName pkgs.youtube-dl 953 | => "youtube-dl" 954 | ``` 955 | ::: 956 | 957 | ## `getVersion` {#getVersion} 958 | 959 | This function takes an argument that's either a derivation or a 960 | derivation's "name" attribute and extracts the version part from that 961 | argument. 962 | 963 | `x` 964 | 965 | : Function argument 966 | 967 | 968 | ::: {.example #example-getVersion} 969 | # `getVersion` usage example 970 | 971 | ```nix 972 | getVersion "youtube-dl-2016.01.01" 973 | => "2016.01.01" 974 | getVersion pkgs.youtube-dl 975 | => "2016.01.01" 976 | ``` 977 | ::: 978 | 979 | ## `nameFromURL` {#nameFromURL} 980 | 981 | Extract name with version from URL. Ask for separator which is 982 | supposed to start extension. 983 | 984 | `url` 985 | 986 | : Function argument 987 | 988 | 989 | `sep` 990 | 991 | : Function argument 992 | 993 | 994 | ::: {.example #example-nameFromURL} 995 | # `nameFromURL` usage example 996 | 997 | ```nix 998 | nameFromURL "https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2" "-" 999 | => "nix" 1000 | nameFromURL "https://nixos.org/releases/nix/nix-1.7/nix-1.7-x86_64-linux.tar.bz2" "_" 1001 | => "nix-1.7-x86" 1002 | ``` 1003 | ::: 1004 | 1005 | ## `mesonOption` {#mesonOption} 1006 | 1007 | **Type**: 1008 | ``` 1009 | mesonOption :: string -> string -> string 1010 | 1011 | @param feature The feature to be set 1012 | @param value The desired value 1013 | ``` 1014 | 1015 | Create a -D= string that can be passed to typical Meson 1016 | invocations. 1017 | 1018 | `feature` 1019 | 1020 | : Function argument 1021 | 1022 | 1023 | `value` 1024 | 1025 | : Function argument 1026 | 1027 | 1028 | ::: {.example #example-mesonOption} 1029 | # `mesonOption` usage example 1030 | 1031 | ```nix 1032 | mesonOption "engine" "opengl" 1033 | => "-Dengine=opengl" 1034 | ``` 1035 | ::: 1036 | 1037 | ## `mesonBool` {#mesonBool} 1038 | 1039 | **Type**: 1040 | ``` 1041 | mesonBool :: string -> bool -> string 1042 | 1043 | @param condition The condition to be made true or false 1044 | @param flag The controlling flag of the condition 1045 | ``` 1046 | 1047 | Create a -D={true,false} string that can be passed to typical 1048 | Meson invocations. 1049 | 1050 | `condition` 1051 | 1052 | : Function argument 1053 | 1054 | 1055 | `flag` 1056 | 1057 | : Function argument 1058 | 1059 | 1060 | ::: {.example #example-mesonBool} 1061 | # `mesonBool` usage example 1062 | 1063 | ```nix 1064 | mesonBool "hardened" true 1065 | => "-Dhardened=true" 1066 | mesonBool "static" false 1067 | => "-Dstatic=false" 1068 | ``` 1069 | ::: 1070 | 1071 | ## `mesonEnable` {#mesonEnable} 1072 | 1073 | **Type**: 1074 | ``` 1075 | mesonEnable :: string -> bool -> string 1076 | 1077 | @param feature The feature to be enabled or disabled 1078 | @param flag The controlling flag 1079 | ``` 1080 | 1081 | Create a -D={enabled,disabled} string that can be passed to 1082 | typical Meson invocations. 1083 | 1084 | `feature` 1085 | 1086 | : Function argument 1087 | 1088 | 1089 | `flag` 1090 | 1091 | : Function argument 1092 | 1093 | 1094 | ::: {.example #example-mesonEnable} 1095 | # `mesonEnable` usage example 1096 | 1097 | ```nix 1098 | mesonEnable "docs" true 1099 | => "-Ddocs=enabled" 1100 | mesonEnable "savage" false 1101 | => "-Dsavage=disabled" 1102 | ``` 1103 | ::: 1104 | 1105 | ## `enableFeature` {#enableFeature} 1106 | 1107 | Create an --{enable,disable}- string that can be passed to 1108 | standard GNU Autoconf scripts. 1109 | 1110 | `enable` 1111 | 1112 | : Function argument 1113 | 1114 | 1115 | `feat` 1116 | 1117 | : Function argument 1118 | 1119 | 1120 | ::: {.example #example-enableFeature} 1121 | # `enableFeature` usage example 1122 | 1123 | ```nix 1124 | enableFeature true "shared" 1125 | => "--enable-shared" 1126 | enableFeature false "shared" 1127 | => "--disable-shared" 1128 | ``` 1129 | ::: 1130 | 1131 | ## `enableFeatureAs` {#enableFeatureAs} 1132 | 1133 | Create an --{enable-=,disable-} string that can be passed to 1134 | standard GNU Autoconf scripts. 1135 | 1136 | `enable` 1137 | 1138 | : Function argument 1139 | 1140 | 1141 | `feat` 1142 | 1143 | : Function argument 1144 | 1145 | 1146 | `value` 1147 | 1148 | : Function argument 1149 | 1150 | 1151 | ::: {.example #example-enableFeatureAs} 1152 | # `enableFeatureAs` usage example 1153 | 1154 | ```nix 1155 | enableFeatureAs true "shared" "foo" 1156 | => "--enable-shared=foo" 1157 | enableFeatureAs false "shared" (throw "ignored") 1158 | => "--disable-shared" 1159 | ``` 1160 | ::: 1161 | 1162 | ## `withFeature` {#withFeature} 1163 | 1164 | Create an --{with,without}- string that can be passed to 1165 | standard GNU Autoconf scripts. 1166 | 1167 | `with_` 1168 | 1169 | : Function argument 1170 | 1171 | 1172 | `feat` 1173 | 1174 | : Function argument 1175 | 1176 | 1177 | ::: {.example #example-withFeature} 1178 | # `withFeature` usage example 1179 | 1180 | ```nix 1181 | withFeature true "shared" 1182 | => "--with-shared" 1183 | withFeature false "shared" 1184 | => "--without-shared" 1185 | ``` 1186 | ::: 1187 | 1188 | ## `withFeatureAs` {#withFeatureAs} 1189 | 1190 | Create an --{with-=,without-} string that can be passed to 1191 | standard GNU Autoconf scripts. 1192 | 1193 | `with_` 1194 | 1195 | : Function argument 1196 | 1197 | 1198 | `feat` 1199 | 1200 | : Function argument 1201 | 1202 | 1203 | `value` 1204 | 1205 | : Function argument 1206 | 1207 | 1208 | ::: {.example #example-withFeatureAs} 1209 | # `withFeatureAs` usage example 1210 | 1211 | ```nix 1212 | withFeatureAs true "shared" "foo" 1213 | => "--with-shared=foo" 1214 | withFeatureAs false "shared" (throw "ignored") 1215 | => "--without-shared" 1216 | ``` 1217 | ::: 1218 | 1219 | ## `fixedWidthString` {#fixedWidthString} 1220 | 1221 | **Type**: `fixedWidthString :: int -> string -> string -> string` 1222 | 1223 | Create a fixed width string with additional prefix to match 1224 | required width. 1225 | 1226 | This function will fail if the input string is longer than the 1227 | requested length. 1228 | 1229 | `width` 1230 | 1231 | : Function argument 1232 | 1233 | 1234 | `filler` 1235 | 1236 | : Function argument 1237 | 1238 | 1239 | `str` 1240 | 1241 | : Function argument 1242 | 1243 | 1244 | ::: {.example #example-fixedWidthString} 1245 | # `fixedWidthString` usage example 1246 | 1247 | ```nix 1248 | fixedWidthString 5 "0" (toString 15) 1249 | => "00015" 1250 | ``` 1251 | ::: 1252 | 1253 | ## `fixedWidthNumber` {#fixedWidthNumber} 1254 | 1255 | Format a number adding leading zeroes up to fixed width. 1256 | 1257 | `width` 1258 | 1259 | : Function argument 1260 | 1261 | 1262 | `n` 1263 | 1264 | : Function argument 1265 | 1266 | 1267 | ::: {.example #example-fixedWidthNumber} 1268 | # `fixedWidthNumber` usage example 1269 | 1270 | ```nix 1271 | fixedWidthNumber 5 15 1272 | => "00015" 1273 | ``` 1274 | ::: 1275 | 1276 | ## `floatToString` {#floatToString} 1277 | 1278 | Convert a float to a string, but emit a warning when precision is lost 1279 | during the conversion 1280 | 1281 | `float` 1282 | 1283 | : Function argument 1284 | 1285 | 1286 | ::: {.example #example-floatToString} 1287 | # `floatToString` usage example 1288 | 1289 | ```nix 1290 | floatToString 0.000001 1291 | => "0.000001" 1292 | floatToString 0.0000001 1293 | => trace: warning: Imprecise conversion from float to string 0.000000 1294 | "0.000000" 1295 | ``` 1296 | ::: 1297 | 1298 | ## `isCoercibleToString` {#isCoercibleToString} 1299 | 1300 | Soft-deprecated function. While the original implementation is available as 1301 | isConvertibleWithToString, consider using isStringLike instead, if suitable. 1302 | 1303 | ## `isConvertibleWithToString` {#isConvertibleWithToString} 1304 | 1305 | Check whether a list or other value can be passed to toString. 1306 | 1307 | Many types of value are coercible to string this way, including int, float, 1308 | null, bool, list of similarly coercible values. 1309 | 1310 | `x` 1311 | 1312 | : Function argument 1313 | 1314 | 1315 | ## `isStringLike` {#isStringLike} 1316 | 1317 | Check whether a value can be coerced to a string. 1318 | The value must be a string, path, or attribute set. 1319 | 1320 | String-like values can be used without explicit conversion in 1321 | string interpolations and in most functions that expect a string. 1322 | 1323 | `x` 1324 | 1325 | : Function argument 1326 | 1327 | 1328 | ## `isStorePath` {#isStorePath} 1329 | 1330 | Check whether a value is a store path. 1331 | 1332 | `x` 1333 | 1334 | : Function argument 1335 | 1336 | 1337 | ::: {.example #example-isStorePath} 1338 | # `isStorePath` usage example 1339 | 1340 | ```nix 1341 | isStorePath "/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11/bin/python" 1342 | => false 1343 | isStorePath "/nix/store/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11" 1344 | => true 1345 | isStorePath pkgs.python 1346 | => true 1347 | isStorePath [] || isStorePath 42 || isStorePath {} || … 1348 | => false 1349 | ``` 1350 | ::: 1351 | 1352 | ## `toInt` {#toInt} 1353 | 1354 | **Type**: `string -> int` 1355 | 1356 | Parse a string as an int. Does not support parsing of integers with preceding zero due to 1357 | ambiguity between zero-padded and octal numbers. See toIntBase10. 1358 | 1359 | `str` 1360 | 1361 | : Function argument 1362 | 1363 | 1364 | ::: {.example #example-toInt} 1365 | # `toInt` usage example 1366 | 1367 | ```nix 1368 | toInt "1337" 1369 | => 1337 1370 | 1371 | toInt "-4" 1372 | => -4 1373 | 1374 | toInt " 123 " 1375 | => 123 1376 | 1377 | toInt "00024" 1378 | => error: Ambiguity in interpretation of 00024 between octal and zero padded integer. 1379 | 1380 | toInt "3.14" 1381 | => error: floating point JSON numbers are not supported 1382 | ``` 1383 | ::: 1384 | 1385 | ## `toIntBase10` {#toIntBase10} 1386 | 1387 | **Type**: `string -> int` 1388 | 1389 | Parse a string as a base 10 int. This supports parsing of zero-padded integers. 1390 | 1391 | `str` 1392 | 1393 | : Function argument 1394 | 1395 | 1396 | ::: {.example #example-toIntBase10} 1397 | # `toIntBase10` usage example 1398 | 1399 | ```nix 1400 | toIntBase10 "1337" 1401 | => 1337 1402 | 1403 | toIntBase10 "-4" 1404 | => -4 1405 | 1406 | toIntBase10 " 123 " 1407 | => 123 1408 | 1409 | toIntBase10 "00024" 1410 | => 24 1411 | 1412 | toIntBase10 "3.14" 1413 | => error: floating point JSON numbers are not supported 1414 | ``` 1415 | ::: 1416 | 1417 | ## `readPathsFromFile` {#readPathsFromFile} 1418 | 1419 | Read a list of paths from `file`, relative to the `rootPath`. 1420 | Lines beginning with `#` are treated as comments and ignored. 1421 | Whitespace is significant. 1422 | 1423 | NOTE: This function is not performant and should be avoided. 1424 | 1425 | ::: {.example #example-readPathsFromFile} 1426 | # `readPathsFromFile` usage example 1427 | 1428 | ```nix 1429 | readPathsFromFile /prefix 1430 | ./pkgs/development/libraries/qt-5/5.4/qtbase/series 1431 | => [ "/prefix/dlopen-resolv.patch" "/prefix/tzdir.patch" 1432 | "/prefix/dlopen-libXcursor.patch" "/prefix/dlopen-openssl.patch" 1433 | "/prefix/dlopen-dbus.patch" "/prefix/xdg-config-dirs.patch" 1434 | "/prefix/nix-profiles-library-paths.patch" 1435 | "/prefix/compose-search-path.patch" ] 1436 | ``` 1437 | ::: 1438 | 1439 | ## `fileContents` {#fileContents} 1440 | 1441 | **Type**: `fileContents :: path -> string` 1442 | 1443 | Read the contents of a file removing the trailing \n 1444 | 1445 | `file` 1446 | 1447 | : Function argument 1448 | 1449 | 1450 | ::: {.example #example-fileContents} 1451 | # `fileContents` usage example 1452 | 1453 | ```nix 1454 | $ echo "1.0" > ./version 1455 | 1456 | fileContents ./version 1457 | => "1.0" 1458 | ``` 1459 | ::: 1460 | 1461 | ## `sanitizeDerivationName` {#sanitizeDerivationName} 1462 | 1463 | **Type**: `sanitizeDerivationName :: String -> String` 1464 | 1465 | Creates a valid derivation name from a potentially invalid one. 1466 | 1467 | ::: {.example #example-sanitizeDerivationName} 1468 | # `sanitizeDerivationName` usage example 1469 | 1470 | ```nix 1471 | sanitizeDerivationName "../hello.bar # foo" 1472 | => "-hello.bar-foo" 1473 | sanitizeDerivationName "" 1474 | => "unknown" 1475 | sanitizeDerivationName pkgs.hello 1476 | => "-nix-store-2g75chlbpxlrqn15zlby2dfh8hr9qwbk-hello-2.10" 1477 | ``` 1478 | ::: 1479 | 1480 | ## `levenshtein` {#levenshtein} 1481 | 1482 | **Type**: `levenshtein :: string -> string -> int` 1483 | 1484 | Computes the Levenshtein distance between two strings. 1485 | Complexity O(n*m) where n and m are the lengths of the strings. 1486 | Algorithm adjusted from https://stackoverflow.com/a/9750974/6605742 1487 | 1488 | `a` 1489 | 1490 | : Function argument 1491 | 1492 | 1493 | `b` 1494 | 1495 | : Function argument 1496 | 1497 | 1498 | ::: {.example #example-levenshtein} 1499 | # `levenshtein` usage example 1500 | 1501 | ```nix 1502 | levenshtein "foo" "foo" 1503 | => 0 1504 | levenshtein "book" "hook" 1505 | => 1 1506 | levenshtein "hello" "Heyo" 1507 | => 3 1508 | ``` 1509 | ::: 1510 | 1511 | ## `commonPrefixLength` {#commonPrefixLength} 1512 | 1513 | Returns the length of the prefix common to both strings. 1514 | 1515 | `a` 1516 | 1517 | : Function argument 1518 | 1519 | 1520 | `b` 1521 | 1522 | : Function argument 1523 | 1524 | 1525 | ## `commonSuffixLength` {#commonSuffixLength} 1526 | 1527 | Returns the length of the suffix common to both strings. 1528 | 1529 | `a` 1530 | 1531 | : Function argument 1532 | 1533 | 1534 | `b` 1535 | 1536 | : Function argument 1537 | 1538 | 1539 | ## `levenshteinAtMost` {#levenshteinAtMost} 1540 | 1541 | **Type**: `levenshteinAtMost :: int -> string -> string -> bool` 1542 | 1543 | Returns whether the levenshtein distance between two strings is at most some value 1544 | Complexity is O(min(n,m)) for k <= 2 and O(n*m) otherwise 1545 | 1546 | ::: {.example #example-levenshteinAtMost} 1547 | # `levenshteinAtMost` usage example 1548 | 1549 | ```nix 1550 | levenshteinAtMost 0 "foo" "foo" 1551 | => true 1552 | levenshteinAtMost 1 "foo" "boa" 1553 | => false 1554 | levenshteinAtMost 2 "foo" "boa" 1555 | => true 1556 | levenshteinAtMost 2 "This is a sentence" "this is a sentense." 1557 | => false 1558 | levenshteinAtMost 3 "This is a sentence" "this is a sentense." 1559 | => true 1560 | ``` 1561 | ::: 1562 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__multi_line.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/main.rs 3 | expression: output 4 | --- 5 | ## `lib.let.f` {#function-library-lib.let.f} 6 | 7 | Some description 8 | 9 | structured function argument 10 | 11 | : `x` 12 | 13 | : First line 14 | 15 | Second line 16 | 17 | 18 | ## `lib.let.g` {#function-library-lib.let.g} 19 | 20 | Some other description 21 | 22 | structured function argument 23 | 24 | : `x` 25 | 26 | : First line 27 | 28 | Second line 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/snapshots/nixdoc__test__patterns.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/test.rs 3 | expression: output 4 | --- 5 | ## `lib.debug.iAmTopLevel` {#function-library-lib.debug.iAmTopLevel} 6 | 7 | This binding is in the top-level attrset 8 | -------------------------------------------------------------------------------- /src/test.rs: -------------------------------------------------------------------------------- 1 | use rnix; 2 | use std::fs; 3 | use std::path::PathBuf; 4 | 5 | use crate::{ 6 | collect_entries, format::shift_headings, main_with_options, retrieve_description, ManualEntry, 7 | Options, 8 | }; 9 | 10 | #[test] 11 | fn test_main() { 12 | let options = Options { 13 | prefix: String::from("lib"), 14 | anchor_prefix: String::from("function-library-"), 15 | json_output: false, 16 | category: String::from("strings"), 17 | description: String::from("string manipulation functions"), 18 | file: PathBuf::from("test/strings.nix"), 19 | locs: Some(PathBuf::from("test/strings.json")), 20 | }; 21 | 22 | let output = main_with_options(options); 23 | 24 | insta::assert_snapshot!(output); 25 | } 26 | 27 | #[test] 28 | fn test_main_minimal() { 29 | let options = Options { 30 | prefix: String::from(""), 31 | anchor_prefix: String::from(""), 32 | json_output: false, 33 | category: String::from(""), 34 | description: String::from(""), 35 | file: PathBuf::from("test/strings.nix"), 36 | locs: Some(PathBuf::from("test/strings.json")), 37 | }; 38 | 39 | let output = main_with_options(options); 40 | 41 | insta::assert_snapshot!(output); 42 | } 43 | 44 | #[test] 45 | fn test_json_output() { 46 | let options = Options { 47 | prefix: String::from("lib"), 48 | anchor_prefix: String::from("function-library-"), 49 | json_output: true, 50 | category: String::from("strings"), 51 | description: String::from("string manipulation functions"), 52 | file: PathBuf::from("test/strings.nix"), 53 | locs: Some(PathBuf::from("test/strings.json")), 54 | }; 55 | 56 | let output = main_with_options(options); 57 | 58 | insta::assert_snapshot!(output); 59 | } 60 | 61 | #[test] 62 | fn test_description_of_lib_debug() { 63 | let src = fs::read_to_string("test/lib-debug.nix").unwrap(); 64 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 65 | let prefix = "lib"; 66 | let category = "debug"; 67 | let desc = retrieve_description(&nix, &"Debug", category); 68 | let mut output = String::from(desc) + "\n"; 69 | 70 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 71 | entry.write_section("function-library-", &mut output); 72 | } 73 | 74 | insta::assert_snapshot!(output); 75 | } 76 | 77 | #[test] 78 | fn test_arg_formatting() { 79 | let mut output = String::from(""); 80 | let src = fs::read_to_string("test/arg-formatting.nix").unwrap(); 81 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 82 | let prefix = "lib"; 83 | let category = "options"; 84 | 85 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 86 | entry.write_section("function-library-", &mut output); 87 | } 88 | 89 | insta::assert_snapshot!(output); 90 | } 91 | 92 | #[test] 93 | fn test_inherited_exports() { 94 | let mut output = String::from(""); 95 | let src = fs::read_to_string("test/inherited-exports.nix").unwrap(); 96 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 97 | let prefix = "lib"; 98 | let category = "let"; 99 | 100 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 101 | entry.write_section("function-library-", &mut output); 102 | } 103 | 104 | insta::assert_snapshot!(output); 105 | } 106 | 107 | #[test] 108 | fn test_line_comments() { 109 | let mut output = String::from(""); 110 | let src = fs::read_to_string("test/line-comments.nix").unwrap(); 111 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 112 | let prefix = "lib"; 113 | let category = "let"; 114 | 115 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 116 | entry.write_section("function-library-", &mut output); 117 | } 118 | 119 | insta::assert_snapshot!(output); 120 | } 121 | 122 | #[test] 123 | fn test_multi_line() { 124 | let mut output = String::from(""); 125 | let src = fs::read_to_string("test/multi-line.nix").unwrap(); 126 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 127 | let prefix = "lib"; 128 | let category = "let"; 129 | 130 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 131 | entry.write_section("function-library-", &mut output); 132 | } 133 | 134 | insta::assert_snapshot!(output); 135 | } 136 | 137 | #[test] 138 | fn test_doc_comment() { 139 | let mut output = String::from(""); 140 | let src = fs::read_to_string("test/doc-comment.nix").unwrap(); 141 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 142 | let prefix = "lib"; 143 | let category = "debug"; 144 | 145 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 146 | entry.write_section("function-library-", &mut output); 147 | } 148 | 149 | insta::assert_snapshot!(output); 150 | } 151 | 152 | #[test] 153 | fn test_commonmark() { 154 | let src = fs::read_to_string("test/commonmark.md").unwrap(); 155 | 156 | let output = shift_headings(&src, 0); 157 | 158 | insta::assert_snapshot!(output); 159 | } 160 | 161 | #[test] 162 | fn test_headings() { 163 | let src = fs::read_to_string("test/headings.md").unwrap(); 164 | 165 | let output = shift_headings(&src, 2); 166 | 167 | insta::assert_snapshot!(output); 168 | } 169 | 170 | #[test] 171 | fn test_doc_comment_section_description() { 172 | let src = fs::read_to_string("test/doc-comment-sec-heading.nix").unwrap(); 173 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 174 | let prefix = "lib"; 175 | let category = "debug"; 176 | let desc = retrieve_description(&nix, &"Debug", category); 177 | let mut output = String::from(desc) + "\n"; 178 | 179 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 180 | entry.write_section("function-library-", &mut output); 181 | } 182 | 183 | insta::assert_snapshot!(output); 184 | } 185 | 186 | #[test] 187 | fn test_doc_comment_no_duplicate_arguments() { 188 | let src = fs::read_to_string("test/doc-comment-arguments.nix").unwrap(); 189 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 190 | let prefix = "lib"; 191 | let category = "debug"; 192 | let desc = retrieve_description(&nix, &"Debug", category); 193 | let mut output = String::from(desc) + "\n"; 194 | 195 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 196 | entry.write_section("function-library-", &mut output); 197 | } 198 | 199 | insta::assert_snapshot!(output); 200 | } 201 | 202 | #[test] 203 | fn test_empty_prefix() { 204 | let test_entry = ManualEntry { 205 | args: vec![], 206 | category: "test".to_string(), 207 | location: None, 208 | description: vec![], 209 | example: None, 210 | fn_type: None, 211 | name: "mapSimple'".to_string(), 212 | prefix: "".to_string(), 213 | }; 214 | 215 | let (ident, title) = test_entry.get_ident_title(); 216 | 217 | assert_eq!(ident, "test.mapSimple-prime"); 218 | assert_eq!(title, "test.mapSimple'"); 219 | } 220 | 221 | #[test] 222 | fn test_patterns() { 223 | let mut output = String::from(""); 224 | let src = fs::read_to_string("test/patterns.nix").unwrap(); 225 | let nix = rnix::Root::parse(&src).ok().expect("failed to parse input"); 226 | let prefix = "lib"; 227 | let category = "debug"; 228 | 229 | for entry in collect_entries(nix, prefix, category, &Default::default()) { 230 | entry.write_section("function-library-", &mut output); 231 | } 232 | 233 | insta::assert_snapshot!(output); 234 | } 235 | -------------------------------------------------------------------------------- /test/arg-formatting.nix: -------------------------------------------------------------------------------- 1 | { 2 | /* documented function */ 3 | fn = 4 | # single arugment 5 | a: 6 | # set argument 7 | { 8 | # documented argument 9 | default ? null, 10 | # i like this argument. another! 11 | example ? null 12 | } @ args: 13 | 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/commonmark.md: -------------------------------------------------------------------------------- 1 | # Heading 1 2 | 3 | This Markdown includes a variety of elements that you might find in a document parsed to an AST by a Markdown parser following the CommonMark specification. 4 | Feel free to modify or expand upon it based on your specific needs or to explore additional Markdown features. 5 | 6 | ## Heading 2 7 | 8 | ### Heading 3 9 | 10 | #### Heading 4 11 | 12 | ##### Heading 5 13 | 14 | This is a paragraph with some **bold text** and _italic text_. 15 | 16 | > This is a blockquote. 17 | 18 | - This is 19 | - an unordered 20 | - list 21 | 22 | 1. This is 23 | 2. an ordered 24 | 3. list 25 | 26 | `Inline code` spans are also supported. 27 | 28 | ```bash {#example .class} 29 | # This is a code block 30 | echo "Hello, Markdown!" 31 | ``` 32 | 33 | Here is a horizontal rule: 34 | 35 | --- 36 | 37 | ### Links and Images 38 | 39 | [This is a link](https://example.com) 40 | 41 | ![This is an image](https://example.com/image.png "Image Title") 42 | 43 | ### Tables 44 | 45 | | Syntax | Description | 46 | | --------- | ----------- | 47 | | Header | Title | 48 | | Paragraph | Text | 49 | 50 | ### Footnotes 51 | 52 | Here is a text with a footnote[^1]. 53 | 54 | [^1]: This is the footnote. 55 | 56 | ### Inline HTML 57 | 58 | This is bold text using HTML 59 | 60 |
61 | This is a div with red text. 62 |
63 | 64 | ### Task list 65 | 66 | - [x] This is a completed task 67 | - [ ] This is an uncompleted task 68 | 69 | ### Markdown-it-py extensions 70 | 71 | ### Fenced div with attributes 72 | 73 | ::: {#customDiv .customStyle key="value"} 74 | This is a Pandoc-style fenced div with attributes. 75 | ::: 76 | 77 | :::{#ex-makeScope .example} 78 | #### Create an interdependent package set on top of `pkgs` 79 | 80 | The functions in `foo.nix` and `bar.nix` can depend on each other, in the sense that `foo.nix` can contain a function that expects `bar` as an attribute in its argument. 81 | 82 | ```nix 83 | let 84 | pkgs = import { }; 85 | in 86 | pkgs.lib.makeScope pkgs.newScope (self: { 87 | foo = self.callPackage ./foo.nix { }; 88 | bar = self.callPackage ./bar.nix { }; 89 | }) 90 | ``` 91 | 92 | evaluates to 93 | 94 | ```nix 95 | { 96 | callPackage = «lambda»; 97 | newScope = «lambda»; 98 | overrideScope = «lambda»; 99 | packages = «lambda»; 100 | foo = «derivation»; 101 | bar = «derivation»; 102 | } 103 | ``` 104 | ::: 105 | 106 | ### Heading anchors 107 | 108 | #### Simple {#some-id} 109 | 110 | #### With attributes {#some-other-id .customClass style="color:blue;"} 111 | 112 | This heading includes both an anchor and CSS attributes. 113 | 114 | ### Definition List 115 | 116 | Term 1 117 | : Definition 1 118 | 119 | Term 2 120 | : Definition 2 with a **bold** aspect. 121 | 122 | Parent Term 123 | : Parent Definition 124 | 125 | Nested Term 1 126 | : Nested Definition 1 127 | 128 | Nested Term 2 129 | : Nested Definition 2 130 | 131 | ::: {.important} 132 | **Note:** 133 | : This is an important note inside a custom styled div. 134 | ::: 135 | 136 | ### Codeblocks 137 | 138 | ```python 139 | # This is a Python code example 140 | def hello_world(): 141 | print("Hello, world!") 142 | ``` 143 | 144 | Codeblock with attributes 145 | 146 | ```python {#codeExample .highlighted style="background-color: #f0f0f0;"} 147 | # This is a Python code example 148 | def hello_world(): 149 | print("Hello, world!") 150 | ``` 151 | -------------------------------------------------------------------------------- /test/doc-comment-arguments.nix: -------------------------------------------------------------------------------- 1 | { 2 | /* nixdoc comment */ 3 | old = 4 | # Should be visible 5 | arg: 1; 6 | 7 | /** Doc-comment */ 8 | omited = 9 | # Not visible 10 | arg: 1; 11 | 12 | /** Doc-comment */ 13 | multiple = 14 | # Not visible 15 | arg: 16 | /* Not visible */ 17 | foo: 18 | /** Not visible */ 19 | bar: 20 | 1; 21 | 22 | /** 23 | Doc-comment before the lamdba causes the whole 24 | lambda including its arguments to switch to doc-comments ONLY rendering 25 | */ 26 | argumentTest = { 27 | # Legacy line comment 28 | formal1, 29 | # Legacy 30 | # Block 31 | formal2, 32 | /* 33 | Legacy 34 | multiline 35 | comment 36 | */ 37 | formal3, 38 | /** 39 | Not shown yet 40 | */ 41 | formal4, 42 | 43 | }: 44 | {}; 45 | 46 | /* 47 | Legacy comments allow to use any 48 | form of comments for the lambda arguments/formals 49 | */ 50 | legacyArgumentTest = { 51 | # Legacy line comment 52 | formal1, 53 | # Legacy 54 | # Block 55 | formal2, 56 | /* 57 | Legacy 58 | multiline 59 | comment 60 | */ 61 | formal3, 62 | /** 63 | doc-comment style 64 | */ 65 | formal4, 66 | 67 | }: 68 | {}; 69 | } -------------------------------------------------------------------------------- /test/doc-comment-sec-heading.nix: -------------------------------------------------------------------------------- 1 | /** 2 | Markdown section heading 3 | */ 4 | {}:{} 5 | -------------------------------------------------------------------------------- /test/doc-comment.nix: -------------------------------------------------------------------------------- 1 | { 2 | # not a doc comment 3 | hidden = a: a; 4 | 5 | /* 6 | nixdoc-legacy comment 7 | 8 | Example: 9 | 10 | This is a parsed example 11 | 12 | Type: 13 | 14 | This is a parsed type 15 | */ 16 | nixdoc = {}; 17 | 18 | /** 19 | doc comment in markdown format 20 | */ 21 | rfc-style = {}; 22 | 23 | # Omitting a doc comment from an attribute doesn't duplicate the previous one 24 | /** Comment */ 25 | foo = 0; 26 | 27 | # This should not have any docs 28 | bar = 1; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /test/headings.md: -------------------------------------------------------------------------------- 1 | # h1-heading 2 | 3 | ## h2-heading 4 | 5 | 3 leading whitespaces are okay for headings 6 | 7 | ## h2 heading 8 | 9 | # code block 10 | 11 | 12 | ## h2-heading-with-id {#some-id} 13 | 14 | Indented code block 15 | 16 | # Code comment 17 | a = 1; 18 | 19 | ### h3-heading 20 | 21 | ```nix 22 | # A comment should not be shifted 23 | ``` 24 | 25 | ### annother heading 26 | 27 | ``` 28 | # Some pseudocode 29 | map a from b -> 1 30 | ``` 31 | 32 | ### indented (0-3) fences 33 | 34 | 3 leading whitespaces are okay for code fences 35 | 36 | ``` lang info 37 | # Some pseudocode 38 | map a from b -> 1 39 | ``` 40 | 41 | ### indented (0-3) fences asymmetric 42 | 43 | ``` 44 | # Some pseudocode 45 | map a from b -> 1 46 | ``` 47 | 48 | ### More closing fences than opening 49 | 50 | ```` 51 | # Some pseudocode 52 | map a from b -> 1 53 | ``````` 54 | 55 | ### Some heading 56 | 57 | ````nix 58 | /** 59 | ```nix 60 | # A nested comment should not be shifted 61 | ``` 62 | */ 63 | 1 64 | # A comment 65 | ```` 66 | 67 | #### h4-heading 68 | 69 | Nested tilde fences 70 | 71 | ~~~~~nix 72 | /* 73 | ~~~~nix 74 | /** 75 | ~~~nix 76 | # A nested comment should not be shifted 77 | 42 78 | ~~~ 79 | */ 80 | 1 81 | # A nested comment ^ 82 | ~~~~ 83 | */ 84 | # A comment ^ 85 | foo 86 | ~~~~~ 87 | 88 | ##### h5-heading 89 | 90 | Mixed fences 91 | 92 | ~~~nix 93 | /** 94 | ```nix 95 | # A nested comment should not be shifted 96 | ``` 97 | */ 98 | 1 99 | # A comment 100 | ~~~ 101 | 102 | ###### h6-heading 103 | 104 | This should be h6 as well 105 | -------------------------------------------------------------------------------- /test/inherited-exports.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | let 4 | /* Concatenate a list of strings. 5 | 6 | Type: concatStrings :: [string] -> string 7 | 8 | Example: 9 | concatStrings ["foo" "bar"] 10 | => "foobar" 11 | */ 12 | concatStrings = builtins.concatStringsSep ""; 13 | 14 | /* this should be ignored because it's inherited from an explicit source */ 15 | from = a: a; 16 | in { 17 | inherit concatStrings; 18 | inherit ({}) from; 19 | 20 | foo1 = { 21 | /* this should be ignored because it's in a nested attrset */ 22 | bar = a: a; 23 | }; 24 | 25 | /* this should be found */ 26 | foo2 = 27 | let 28 | /* this should be ignored because it's in a nested let */ 29 | bar = a: a; 30 | in bar; 31 | } 32 | -------------------------------------------------------------------------------- /test/lib-debug.nix: -------------------------------------------------------------------------------- 1 | /* Collection of functions useful for debugging 2 | broken nix expressions. 3 | 4 | * `trace`-like functions take two values, print 5 | the first to stderr and return the second. 6 | * `traceVal`-like functions take one argument 7 | which both printed and returned. 8 | * `traceSeq`-like functions fully evaluate their 9 | traced value before printing (not just to “weak 10 | head normal form” like trace does by default). 11 | * Functions that end in `-Fn` take an additional 12 | function as their first argument, which is applied 13 | to the traced value before it is printed. 14 | */ 15 | { lib }: 16 | let 17 | inherit (lib) 18 | isList 19 | isAttrs 20 | substring 21 | attrValues 22 | concatLists 23 | const 24 | elem 25 | generators 26 | id 27 | mapAttrs 28 | trace; 29 | 30 | # -- TRACING -- 31 | 32 | /* Conditionally trace the supplied message, based on a predicate. 33 | 34 | Type: traceIf :: bool -> string -> a -> a 35 | 36 | Example: 37 | traceIf true "hello" 3 38 | trace: hello 39 | => 3 40 | */ 41 | traceIf = 42 | # Predicate to check 43 | pred: 44 | # Message that should be traced 45 | msg: 46 | # Value to return 47 | x: if pred then trace msg x else x; 48 | 49 | /* Trace the supplied value after applying a function to it, and 50 | return the original value. 51 | 52 | Type: traceValFn :: (a -> b) -> a -> a 53 | 54 | Example: 55 | traceValFn (v: "mystring ${v}") "foo" 56 | trace: mystring foo 57 | => "foo" 58 | */ 59 | traceValFn = 60 | # Function to apply 61 | f: 62 | # Value to trace and return 63 | x: trace (f x) x; 64 | 65 | /* Trace the supplied value and return it. 66 | 67 | Type: traceVal :: a -> a 68 | 69 | Example: 70 | traceVal 42 71 | # trace: 42 72 | => 42 73 | */ 74 | traceVal = traceValFn id; 75 | 76 | /* `builtins.trace`, but the value is `builtins.deepSeq`ed first. 77 | 78 | Type: traceSeq :: a -> b -> b 79 | 80 | Example: 81 | trace { a.b.c = 3; } null 82 | trace: { a = ; } 83 | => null 84 | traceSeq { a.b.c = 3; } null 85 | trace: { a = { b = { c = 3; }; }; } 86 | => null 87 | */ 88 | traceSeq = 89 | # The value to trace 90 | x: 91 | # The value to return 92 | y: trace (builtins.deepSeq x x) y; 93 | 94 | 95 | # Helpers for traceSeqN 96 | snip = v: 97 | if isList v then noQuotes "[…]" v 98 | else if isAttrs v then noQuotes "{…}" v 99 | else v; 100 | 101 | noQuotes = str: v: { __pretty = const str; val = v; }; 102 | 103 | modify = n: fn: v: 104 | if (n == 0) then fn v 105 | else if isList v then map (modify (n - 1) fn) v 106 | else if isAttrs v then mapAttrs (const (modify (n - 1) fn)) v 107 | else v; 108 | 109 | /* Like `traceSeq`, but only evaluate down to depth n. 110 | This is very useful because lots of `traceSeq` usages 111 | lead to an infinite recursion. 112 | 113 | Example: 114 | traceSeqN 2 { a.b.c = 3; } null 115 | trace: { a = { b = {…}; }; } 116 | => null 117 | 118 | Type: traceSeqN :: Int -> a -> b -> b 119 | */ 120 | traceSeqN = depth: x: y: 121 | trace (generators.toPretty { allowPrettyValues = true; } (modify depth snip x)) y; 122 | 123 | /* A combination of `traceVal` and `traceSeq` that applies a 124 | provided function to the value to be traced after `deepSeq`ing 125 | it. 126 | */ 127 | traceValSeqFn = 128 | # Function to apply 129 | f: 130 | # Value to trace 131 | v: traceValFn f (builtins.deepSeq v v); 132 | 133 | /* A combination of `traceVal` and `traceSeq`. */ 134 | traceValSeq = traceValSeqFn id; 135 | 136 | /* A combination of `traceVal` and `traceSeqN` that applies a 137 | provided function to the value to be traced. */ 138 | traceValSeqNFn = 139 | # Function to apply 140 | f: 141 | depth: 142 | # Value to trace 143 | v: traceSeqN depth (f v) v; 144 | 145 | /* A combination of `traceVal` and `traceSeqN`. */ 146 | traceValSeqN = traceValSeqNFn id; 147 | 148 | /* Trace the input and output of a function `f` named `name`, 149 | both down to `depth`. 150 | 151 | This is useful for adding around a function call, 152 | to see the before/after of values as they are transformed. 153 | 154 | Example: 155 | traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } 156 | trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; } 157 | => { a.b.c = 3; } 158 | */ 159 | traceFnSeqN = depth: name: f: v: 160 | let res = f v; 161 | in lib.traceSeqN 162 | (depth + 1) 163 | { 164 | fn = name; 165 | from = v; 166 | to = res; 167 | } 168 | res; 169 | 170 | 171 | # -- TESTING -- 172 | 173 | /* Evaluates a set of tests. 174 | 175 | A test is an attribute set `{expr, expected}`, 176 | denoting an expression and its expected result. 177 | 178 | The result is a `list` of __failed tests__, each represented as 179 | `{name, expected, result}`, 180 | 181 | - expected 182 | - What was passed as `expected` 183 | - result 184 | - The actual `result` of the test 185 | 186 | Used for regression testing of the functions in lib; see 187 | tests.nix for more examples. 188 | 189 | Important: Only attributes that start with `test` are executed. 190 | 191 | - If you want to run only a subset of the tests add the attribute `tests = ["testName"];` 192 | 193 | Example: 194 | 195 | runTests { 196 | testAndOk = { 197 | expr = lib.and true false; 198 | expected = false; 199 | }; 200 | testAndFail = { 201 | expr = lib.and true false; 202 | expected = true; 203 | }; 204 | } 205 | -> 206 | [ 207 | { 208 | name = "testAndFail"; 209 | expected = true; 210 | result = false; 211 | } 212 | ] 213 | 214 | Type: 215 | runTests :: { 216 | tests = [ String ]; 217 | ${testName} :: { 218 | expr :: a; 219 | expected :: a; 220 | }; 221 | } 222 | -> 223 | [ 224 | { 225 | name :: String; 226 | expected :: a; 227 | result :: a; 228 | } 229 | ] 230 | */ 231 | runTests = 232 | # Tests to run 233 | tests: concatLists (attrValues (mapAttrs (name: test: 234 | let testsToRun = if tests ? tests then tests.tests else []; 235 | in if (substring 0 4 name == "test" || elem name testsToRun) 236 | && ((testsToRun == []) || elem name tests.tests) 237 | && (test.expr != test.expected) 238 | 239 | then [ { inherit name; expected = test.expected; result = test.expr; } ] 240 | else [] ) tests)); 241 | 242 | /* Create a test assuming that list elements are `true`. 243 | 244 | Example: 245 | { testX = allTrue [ true ]; } 246 | */ 247 | testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; 248 | 249 | in 250 | 251 | # This is the public interface of the file. The order of the entries in the inherit list is the 252 | # order in which they will be documented by `nixdoc`. 253 | { 254 | inherit 255 | traceIf 256 | traceValFn 257 | traceVal 258 | traceSeq 259 | traceSeqN 260 | traceValSeqFn 261 | traceValSeq 262 | traceValSeqNFn 263 | traceValSeqN 264 | traceFnSeqN 265 | runTests 266 | testAllTrue 267 | ; 268 | } 269 | -------------------------------------------------------------------------------- /test/line-comments.nix: -------------------------------------------------------------------------------- 1 | { 2 | # not a doc comment 3 | hidden = a: a; 4 | 5 | /* is a doc comment */ 6 | shown = 7 | # a doc comment 8 | a: 9 | /* also a doc comment */ 10 | b: 11 | # a doc comment 12 | # with continuation 13 | c: 14 | {}; 15 | } 16 | -------------------------------------------------------------------------------- /test/multi-line.nix: -------------------------------------------------------------------------------- 1 | { 2 | /* Some description */ 3 | f = 4 | { 5 | /* First line 6 | 7 | Second line 8 | */ 9 | x 10 | }: x; 11 | 12 | /* Some other description */ 13 | g = 14 | { 15 | /* 16 | First line 17 | 18 | Second line 19 | */ 20 | x 21 | }: x; 22 | } 23 | -------------------------------------------------------------------------------- /test/patterns.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? import 3 | # | This attrset must be skipped -- it is not the top-level attrset 4 | # ↓ even though it comes first! 5 | { } 6 | }: 7 | 8 | { 9 | /** 10 | This binding is in the top-level attrset 11 | */ 12 | iAmTopLevel = null; 13 | } 14 | -------------------------------------------------------------------------------- /test/strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib.strings.addContextFrom": "[lib/strings.nix:587](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L587) in ``", 3 | "lib.strings.charToInt": "[lib/strings.nix:378](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L378) in ``", 4 | "lib.strings.commonPrefixLength": "[lib/strings.nix:1151](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1151) in ``", 5 | "lib.strings.commonSuffixLength": "[lib/strings.nix:1159](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1159) in ``", 6 | "lib.strings.compareVersions": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 7 | "lib.strings.concatImapStrings": "[lib/strings.nix:70](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L70) in ``", 8 | "lib.strings.concatImapStringsSep": "[lib/strings.nix:127](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L127) in ``", 9 | "lib.strings.concatLines": "[lib/strings.nix:144](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L144) in ``", 10 | "lib.strings.concatMapStrings": "[lib/strings.nix:59](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L59) in ``", 11 | "lib.strings.concatMapStringsSep": "[lib/strings.nix:110](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L110) in ``", 12 | "lib.strings.concatStrings": "[lib/strings.nix:49](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L49) in ``", 13 | "lib.strings.concatStringsSep": "[lib/strings.nix:97](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L97) in ``", 14 | "lib.strings.elem": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 15 | "lib.strings.elemAt": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 16 | "lib.strings.enableFeature": "[lib/strings.nix:806](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L806) in ``", 17 | "lib.strings.enableFeatureAs": "[lib/strings.nix:819](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L819) in ``", 18 | "lib.strings.escape": "[lib/strings.nix:389](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L389) in ``", 19 | "lib.strings.escapeC": "[lib/strings.nix:402](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L402) in ``", 20 | "lib.strings.escapeNixIdentifier": "[lib/strings.nix:529](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L529) in ``", 21 | "lib.strings.escapeNixString": "[lib/strings.nix:507](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L507) in ``", 22 | "lib.strings.escapeRegex": "[lib/strings.nix:517](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L517) in ``", 23 | "lib.strings.escapeShellArg": "[lib/strings.nix:427](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L427) in ``", 24 | "lib.strings.escapeShellArgs": "[lib/strings.nix:437](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L437) in ``", 25 | "lib.strings.escapeURL": "[lib/strings.nix:413](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L413) in ``", 26 | "lib.strings.escapeXML": "[lib/strings.nix:543](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L543) in ``", 27 | "lib.strings.fileContents": "[lib/strings.nix:1076](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1076) in ``", 28 | "lib.strings.filter": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 29 | "lib.strings.fixedWidthNumber": "[lib/strings.nix:874](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L874) in ``", 30 | "lib.strings.fixedWidthString": "[lib/strings.nix:857](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L857) in ``", 31 | "lib.strings.floatToString": "[lib/strings.nix:886](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L886) in ``", 32 | "lib.strings.fromJSON": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 33 | "lib.strings.getName": "[lib/strings.nix:702](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L702) in ``", 34 | "lib.strings.getVersion": "[lib/strings.nix:719](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L719) in ``", 35 | "lib.strings.hasInfix": "[lib/strings.nix:317](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L317) in ``", 36 | "lib.strings.hasPrefix": "[lib/strings.nix:254](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L254) in ``", 37 | "lib.strings.hasSuffix": "[lib/strings.nix:280](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L280) in ``", 38 | "lib.strings.head": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 39 | "lib.strings.intersperse": "[lib/strings.nix:80](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L80) in ``", 40 | "lib.strings.isAttrs": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 41 | "lib.strings.isCoercibleToString": "[lib/strings.nix:894](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L894) in ``", 42 | "lib.strings.isConvertibleWithToString": "[lib/strings.nix:903](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L903) in ``", 43 | "lib.strings.isInt": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 44 | "lib.strings.isList": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 45 | "lib.strings.isPath": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 46 | "lib.strings.isStorePath": "[lib/strings.nix:932](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L932) in ``", 47 | "lib.strings.isString": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 48 | "lib.strings.isStringLike": "[lib/strings.nix:914](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L914) in ``", 49 | "lib.strings.isValidPosixName": "[lib/strings.nix:449](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L449) in ``", 50 | "lib.strings.levenshtein": "[lib/strings.nix:1130](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1130) in ``", 51 | "lib.strings.levenshteinAtMost": "[lib/strings.nix:1183](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1183) in ``", 52 | "lib.strings.lowerChars": "[lib/strings.nix:551](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L551) in ``", 53 | "lib.strings.makeBinPath": "[lib/strings.nix:202](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L202) in ``", 54 | "lib.strings.makeLibraryPath": "[lib/strings.nix:193](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L193) in ``", 55 | "lib.strings.makeSearchPath": "[lib/strings.nix:157](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L157) in ``", 56 | "lib.strings.makeSearchPathOutput": "[lib/strings.nix:175](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L175) in ``", 57 | "lib.strings.match": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 58 | "lib.strings.mesonBool": "[lib/strings.nix:773](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L773) in ``", 59 | "lib.strings.mesonEnable": "[lib/strings.nix:792](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L792) in ``", 60 | "lib.strings.mesonOption": "[lib/strings.nix:754](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L754) in ``", 61 | "lib.strings.nameFromURL": "[lib/strings.nix:735](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L735) in ``", 62 | "lib.strings.normalizePath": "[lib/strings.nix:212](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L212) in ``", 63 | "lib.strings.optionalString": "[lib/strings.nix:238](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L238) in ``", 64 | "lib.strings.parseDrvName": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 65 | "lib.strings.readFile": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 66 | "lib.strings.readPathsFromFile": "[lib/strings.nix:1056](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1056) in ``", 67 | "lib.strings.removePrefix": "[lib/strings.nix:614](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L614) in ``", 68 | "lib.strings.removeSuffix": "[lib/strings.nix:647](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L647) in ``", 69 | "lib.strings.replaceChars": "[lib/strings.nix:548](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L548) in ``", 70 | "lib.strings.replaceStrings": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 71 | "lib.strings.sanitizeDerivationName": "[lib/strings.nix:1091](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1091) in ``", 72 | "lib.strings.split": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 73 | "lib.strings.splitString": "[lib/strings.nix:598](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L598) in ``", 74 | "lib.strings.storeDir": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 75 | "lib.strings.stringAsChars": "[lib/strings.nix:359](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L359) in ``", 76 | "lib.strings.stringLength": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 77 | "lib.strings.stringToCharacters": "[lib/strings.nix:347](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L347) in ``", 78 | "lib.strings.substring": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 79 | "lib.strings.tail": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 80 | "lib.strings.toInt": "[lib/strings.nix:962](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L962) in ``", 81 | "lib.strings.toIntBase10": "[lib/strings.nix:1013](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L1013) in ``", 82 | "lib.strings.toJSON": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 83 | "lib.strings.toLower": "[lib/strings.nix:562](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L562) in ``", 84 | "lib.strings.toShellVar": "[lib/strings.nix:469](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L469) in ``", 85 | "lib.strings.toShellVars": "[lib/strings.nix:497](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L497) in ``", 86 | "lib.strings.toUpper": "[lib/strings.nix:572](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L572) in ``", 87 | "lib.strings.typeOf": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 88 | "lib.strings.unsafeDiscardStringContext": "[lib/strings.nix:15](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L15) in ``", 89 | "lib.strings.upperChars": "[lib/strings.nix:552](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L552) in ``", 90 | "lib.strings.versionAtLeast": "[lib/strings.nix:690](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L690) in ``", 91 | "lib.strings.versionOlder": "[lib/strings.nix:678](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L678) in ``", 92 | "lib.strings.withFeature": "[lib/strings.nix:830](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L830) in ``", 93 | "lib.strings.withFeatureAs": "[lib/strings.nix:843](https://github.com/NixOS/nixpkgs/blob/580dd2124db98c13c3798af23c2ecf6277ec7d9e/lib/strings.nix#L843) in ``" 94 | } 95 | --------------------------------------------------------------------------------