├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CONFIG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── USAGE.md ├── assets ├── ayu-preview.png ├── gruvbox-preview.png └── light-preview.png ├── example ├── README.md ├── cppdoc.toml ├── extra-pages │ └── extra-page.md ├── include │ └── file.hpp └── static │ ├── ayu.css │ ├── gruvbox.css │ ├── light.css │ ├── onedark.css │ └── style.css └── src ├── comment.rs ├── config.rs ├── doctest.rs ├── main.rs ├── parser.rs ├── render.rs ├── report.rs ├── templates.rs └── templates ├── alias.html ├── docpage.html ├── enum.html ├── function.html ├── index.html ├── macros.html ├── namespace.html ├── page.html ├── record.html └── search.html /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build_and_deploy: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v3 15 | 16 | - name: Install libclang 17 | run: sudo apt-get install -y libclang-dev 18 | 19 | - name: Set up Rust 20 | uses: moonrepo/setup-rust@v1 21 | with: 22 | rust-version: stable 23 | 24 | - name: Cache Cargo registry 25 | uses: actions/cache@v3 26 | with: 27 | path: ~/.cargo/registry 28 | key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 29 | restore-keys: | 30 | ${{ runner.os }}-cargo-registry- 31 | 32 | - name: Cache Cargo build 33 | uses: actions/cache@v3 34 | with: 35 | path: target 36 | key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.toml') }} 37 | restore-keys: | 38 | ${{ runner.os }}-cargo-target- 39 | 40 | - name: Build the project 41 | run: cargo build --release 42 | 43 | - name: Run Cargo project in 'example' directory 44 | run: | 45 | cd example 46 | cargo run --release build 47 | 48 | - name: Deploy docs to GitHub Pages 49 | uses: JamesIves/github-pages-deploy-action@v4 50 | with: 51 | branch: gh-pages 52 | folder: example/docs 53 | token: ${{ secrets.GITHUB_TOKEN }} 54 | 55 | - name: Clean up 56 | run: | 57 | rm -rf example/docs 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | docs 3 | example/docs 4 | -------------------------------------------------------------------------------- /CONFIG.md: -------------------------------------------------------------------------------- 1 | # Configuration options 2 | The configuration file is a TOML file named `cppdoc.toml` with the following sections: 3 | 4 | ## `project` 5 | - `name`: Project name. 6 | - `version`: Project version. 7 | 8 | ## `input` 9 | - `glob`: Glob to use for finding documented files. 10 | - `compiler_arguments`: List of arguments to pass to libclang while parsing code. 11 | 12 | ## `output` 13 | - `static_dir`: Path to a directory containing static files that will be copied in the output directory, this is where `style.css` will typically be located. 14 | - `path`: Path to the output directory. 15 | - `root_namespace` (optional): Namespace to use as the root, this is useful for libraries that only globally expose one namespace and want the index to be based on that namespace. 16 | - `base_url`: Base URL to prepend all paths with. 17 | 18 | ## `pages` 19 | - `index` (optional): Markdown file to use as the index file, if an index page is not specified, the root namespace's comment will be used instead. 20 | - `extra` (optional): List of file paths to serve as extra documentation pages. These may be globs. 21 | 22 | ## `doctests` (optional) 23 | - `enable`: Whether to enable documentation tests or not. 24 | - `run`: Whether to run documentation tests or not (if disabled, tests will only be compiled). 25 | - `compiler_invocation`: Compiler invocation to use to compile documentation tests, this is represented as an array containing `argv`. The sentinel values `{file}` and `{out}` are replaced at runtime by the appropriate values. 26 | 27 | 28 | # Example 29 | 30 | ```toml 31 | [project] 32 | name = "Example" 33 | version = "0.1.0" 34 | 35 | [input] 36 | glob = "include/**/*.hpp" 37 | compiler_arguments = ["-Iinclude", "-std=gnu++20", "-xc++"] 38 | 39 | [pages] 40 | index = "README.md" 41 | extra = ["extra-page.md"] 42 | 43 | [output] 44 | static_dir = "static" 45 | path = "docs" 46 | base_url = "/cppdoc" 47 | 48 | [doctests] 49 | enable = false 50 | run = true 51 | compiler_invocation = ["clang++", "{file}", "-o", "{out}", "-Iinclude", "-std=c++20"] 52 | ``` 53 | -------------------------------------------------------------------------------- /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 = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "android-tzdata" 16 | version = "0.1.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 19 | 20 | [[package]] 21 | name = "android_system_properties" 22 | version = "0.1.5" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 25 | dependencies = [ 26 | "libc", 27 | ] 28 | 29 | [[package]] 30 | name = "anstream" 31 | version = "0.6.18" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 34 | dependencies = [ 35 | "anstyle", 36 | "anstyle-parse", 37 | "anstyle-query", 38 | "anstyle-wincon", 39 | "colorchoice", 40 | "is_terminal_polyfill", 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle" 46 | version = "1.0.10" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 49 | 50 | [[package]] 51 | name = "anstyle-parse" 52 | version = "0.2.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 55 | dependencies = [ 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-query" 61 | version = "1.1.2" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 64 | dependencies = [ 65 | "windows-sys 0.59.0", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-wincon" 70 | version = "3.0.6" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" 73 | dependencies = [ 74 | "anstyle", 75 | "windows-sys 0.59.0", 76 | ] 77 | 78 | [[package]] 79 | name = "anyhow" 80 | version = "1.0.93" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 83 | 84 | [[package]] 85 | name = "autocfg" 86 | version = "1.4.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 89 | 90 | [[package]] 91 | name = "bitflags" 92 | version = "2.6.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 95 | 96 | [[package]] 97 | name = "block-buffer" 98 | version = "0.10.4" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 101 | dependencies = [ 102 | "generic-array", 103 | ] 104 | 105 | [[package]] 106 | name = "bstr" 107 | version = "1.11.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" 110 | dependencies = [ 111 | "memchr", 112 | "serde", 113 | ] 114 | 115 | [[package]] 116 | name = "bumpalo" 117 | version = "3.16.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 120 | 121 | [[package]] 122 | name = "byteorder" 123 | version = "1.5.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 126 | 127 | [[package]] 128 | name = "cc" 129 | version = "1.2.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" 132 | dependencies = [ 133 | "shlex", 134 | ] 135 | 136 | [[package]] 137 | name = "cfg-if" 138 | version = "1.0.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 141 | 142 | [[package]] 143 | name = "chrono" 144 | version = "0.4.38" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 147 | dependencies = [ 148 | "android-tzdata", 149 | "iana-time-zone", 150 | "num-traits", 151 | "windows-targets", 152 | ] 153 | 154 | [[package]] 155 | name = "chrono-tz" 156 | version = "0.9.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" 159 | dependencies = [ 160 | "chrono", 161 | "chrono-tz-build", 162 | "phf", 163 | ] 164 | 165 | [[package]] 166 | name = "chrono-tz-build" 167 | version = "0.3.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" 170 | dependencies = [ 171 | "parse-zoneinfo", 172 | "phf", 173 | "phf_codegen", 174 | ] 175 | 176 | [[package]] 177 | name = "clang" 178 | version = "2.0.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "84c044c781163c001b913cd018fc95a628c50d0d2dfea8bca77dad71edb16e37" 181 | dependencies = [ 182 | "clang-sys", 183 | "libc", 184 | ] 185 | 186 | [[package]] 187 | name = "clang-sys" 188 | version = "1.8.1" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 191 | dependencies = [ 192 | "glob", 193 | "libc", 194 | ] 195 | 196 | [[package]] 197 | name = "clap" 198 | version = "4.5.21" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" 201 | dependencies = [ 202 | "clap_builder", 203 | "clap_derive", 204 | ] 205 | 206 | [[package]] 207 | name = "clap_builder" 208 | version = "4.5.21" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" 211 | dependencies = [ 212 | "anstream", 213 | "anstyle", 214 | "clap_lex", 215 | "strsim", 216 | ] 217 | 218 | [[package]] 219 | name = "clap_derive" 220 | version = "4.5.18" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" 223 | dependencies = [ 224 | "heck", 225 | "proc-macro2", 226 | "quote", 227 | "syn", 228 | ] 229 | 230 | [[package]] 231 | name = "clap_lex" 232 | version = "0.7.3" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" 235 | 236 | [[package]] 237 | name = "colorchoice" 238 | version = "1.0.3" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 241 | 242 | [[package]] 243 | name = "console" 244 | version = "0.15.8" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 247 | dependencies = [ 248 | "encode_unicode", 249 | "lazy_static", 250 | "libc", 251 | "unicode-width 0.1.14", 252 | "windows-sys 0.52.0", 253 | ] 254 | 255 | [[package]] 256 | name = "core-foundation-sys" 257 | version = "0.8.7" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 260 | 261 | [[package]] 262 | name = "cppdoc" 263 | version = "0.1.0" 264 | dependencies = [ 265 | "anyhow", 266 | "clang", 267 | "clap", 268 | "glob", 269 | "indicatif", 270 | "lazy_static", 271 | "pulldown-cmark", 272 | "pygmentize", 273 | "serde", 274 | "serde_json", 275 | "tempfile", 276 | "tera", 277 | "toml", 278 | ] 279 | 280 | [[package]] 281 | name = "cpufeatures" 282 | version = "0.2.15" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" 285 | dependencies = [ 286 | "libc", 287 | ] 288 | 289 | [[package]] 290 | name = "crossbeam-deque" 291 | version = "0.8.5" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 294 | dependencies = [ 295 | "crossbeam-epoch", 296 | "crossbeam-utils", 297 | ] 298 | 299 | [[package]] 300 | name = "crossbeam-epoch" 301 | version = "0.9.18" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 304 | dependencies = [ 305 | "crossbeam-utils", 306 | ] 307 | 308 | [[package]] 309 | name = "crossbeam-utils" 310 | version = "0.8.20" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 313 | 314 | [[package]] 315 | name = "crypto-common" 316 | version = "0.1.6" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 319 | dependencies = [ 320 | "generic-array", 321 | "typenum", 322 | ] 323 | 324 | [[package]] 325 | name = "deunicode" 326 | version = "1.6.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" 329 | 330 | [[package]] 331 | name = "digest" 332 | version = "0.10.7" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 335 | dependencies = [ 336 | "block-buffer", 337 | "crypto-common", 338 | ] 339 | 340 | [[package]] 341 | name = "encode_unicode" 342 | version = "0.3.6" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 345 | 346 | [[package]] 347 | name = "equivalent" 348 | version = "1.0.1" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 351 | 352 | [[package]] 353 | name = "errno" 354 | version = "0.3.9" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 357 | dependencies = [ 358 | "libc", 359 | "windows-sys 0.52.0", 360 | ] 361 | 362 | [[package]] 363 | name = "fastrand" 364 | version = "2.2.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" 367 | 368 | [[package]] 369 | name = "generic-array" 370 | version = "0.14.7" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 373 | dependencies = [ 374 | "typenum", 375 | "version_check", 376 | ] 377 | 378 | [[package]] 379 | name = "getrandom" 380 | version = "0.2.15" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 383 | dependencies = [ 384 | "cfg-if", 385 | "libc", 386 | "wasi", 387 | ] 388 | 389 | [[package]] 390 | name = "glob" 391 | version = "0.3.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 394 | 395 | [[package]] 396 | name = "globset" 397 | version = "0.4.15" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" 400 | dependencies = [ 401 | "aho-corasick", 402 | "bstr", 403 | "log", 404 | "regex-automata", 405 | "regex-syntax", 406 | ] 407 | 408 | [[package]] 409 | name = "globwalk" 410 | version = "0.9.1" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" 413 | dependencies = [ 414 | "bitflags", 415 | "ignore", 416 | "walkdir", 417 | ] 418 | 419 | [[package]] 420 | name = "hashbrown" 421 | version = "0.15.1" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" 424 | 425 | [[package]] 426 | name = "heck" 427 | version = "0.5.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 430 | 431 | [[package]] 432 | name = "humansize" 433 | version = "2.1.3" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" 436 | dependencies = [ 437 | "libm", 438 | ] 439 | 440 | [[package]] 441 | name = "iana-time-zone" 442 | version = "0.1.61" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 445 | dependencies = [ 446 | "android_system_properties", 447 | "core-foundation-sys", 448 | "iana-time-zone-haiku", 449 | "js-sys", 450 | "wasm-bindgen", 451 | "windows-core", 452 | ] 453 | 454 | [[package]] 455 | name = "iana-time-zone-haiku" 456 | version = "0.1.2" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 459 | dependencies = [ 460 | "cc", 461 | ] 462 | 463 | [[package]] 464 | name = "ignore" 465 | version = "0.4.23" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" 468 | dependencies = [ 469 | "crossbeam-deque", 470 | "globset", 471 | "log", 472 | "memchr", 473 | "regex-automata", 474 | "same-file", 475 | "walkdir", 476 | "winapi-util", 477 | ] 478 | 479 | [[package]] 480 | name = "indexmap" 481 | version = "2.6.0" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 484 | dependencies = [ 485 | "equivalent", 486 | "hashbrown", 487 | ] 488 | 489 | [[package]] 490 | name = "indicatif" 491 | version = "0.17.9" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" 494 | dependencies = [ 495 | "console", 496 | "number_prefix", 497 | "portable-atomic", 498 | "unicode-width 0.2.0", 499 | "web-time", 500 | ] 501 | 502 | [[package]] 503 | name = "is_terminal_polyfill" 504 | version = "1.70.1" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 507 | 508 | [[package]] 509 | name = "itoa" 510 | version = "1.0.11" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 513 | 514 | [[package]] 515 | name = "js-sys" 516 | version = "0.3.72" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" 519 | dependencies = [ 520 | "wasm-bindgen", 521 | ] 522 | 523 | [[package]] 524 | name = "lazy_static" 525 | version = "1.5.0" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 528 | 529 | [[package]] 530 | name = "libc" 531 | version = "0.2.162" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" 534 | 535 | [[package]] 536 | name = "libm" 537 | version = "0.2.11" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" 540 | 541 | [[package]] 542 | name = "linux-raw-sys" 543 | version = "0.4.14" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 546 | 547 | [[package]] 548 | name = "log" 549 | version = "0.4.22" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 552 | 553 | [[package]] 554 | name = "memchr" 555 | version = "2.7.4" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 558 | 559 | [[package]] 560 | name = "num-traits" 561 | version = "0.2.19" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 564 | dependencies = [ 565 | "autocfg", 566 | ] 567 | 568 | [[package]] 569 | name = "number_prefix" 570 | version = "0.4.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 573 | 574 | [[package]] 575 | name = "once_cell" 576 | version = "1.20.2" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 579 | 580 | [[package]] 581 | name = "parse-zoneinfo" 582 | version = "0.3.1" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" 585 | dependencies = [ 586 | "regex", 587 | ] 588 | 589 | [[package]] 590 | name = "percent-encoding" 591 | version = "2.3.1" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 594 | 595 | [[package]] 596 | name = "pest" 597 | version = "2.7.14" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" 600 | dependencies = [ 601 | "memchr", 602 | "thiserror", 603 | "ucd-trie", 604 | ] 605 | 606 | [[package]] 607 | name = "pest_derive" 608 | version = "2.7.14" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" 611 | dependencies = [ 612 | "pest", 613 | "pest_generator", 614 | ] 615 | 616 | [[package]] 617 | name = "pest_generator" 618 | version = "2.7.14" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" 621 | dependencies = [ 622 | "pest", 623 | "pest_meta", 624 | "proc-macro2", 625 | "quote", 626 | "syn", 627 | ] 628 | 629 | [[package]] 630 | name = "pest_meta" 631 | version = "2.7.14" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" 634 | dependencies = [ 635 | "once_cell", 636 | "pest", 637 | "sha2", 638 | ] 639 | 640 | [[package]] 641 | name = "phf" 642 | version = "0.11.2" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 645 | dependencies = [ 646 | "phf_shared", 647 | ] 648 | 649 | [[package]] 650 | name = "phf_codegen" 651 | version = "0.11.2" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" 654 | dependencies = [ 655 | "phf_generator", 656 | "phf_shared", 657 | ] 658 | 659 | [[package]] 660 | name = "phf_generator" 661 | version = "0.11.2" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" 664 | dependencies = [ 665 | "phf_shared", 666 | "rand", 667 | ] 668 | 669 | [[package]] 670 | name = "phf_shared" 671 | version = "0.11.2" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 674 | dependencies = [ 675 | "siphasher", 676 | ] 677 | 678 | [[package]] 679 | name = "portable-atomic" 680 | version = "1.9.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" 683 | 684 | [[package]] 685 | name = "ppv-lite86" 686 | version = "0.2.20" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 689 | dependencies = [ 690 | "zerocopy", 691 | ] 692 | 693 | [[package]] 694 | name = "proc-macro2" 695 | version = "1.0.89" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" 698 | dependencies = [ 699 | "unicode-ident", 700 | ] 701 | 702 | [[package]] 703 | name = "pulldown-cmark" 704 | version = "0.12.2" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" 707 | dependencies = [ 708 | "bitflags", 709 | "memchr", 710 | "pulldown-cmark-escape", 711 | "unicase", 712 | ] 713 | 714 | [[package]] 715 | name = "pulldown-cmark-escape" 716 | version = "0.11.0" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" 719 | 720 | [[package]] 721 | name = "pygmentize" 722 | version = "0.2.0" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "ee7d15fa1e045a1c43cec886ec58bd58e845176654119930d3642d84be69b453" 725 | dependencies = [ 726 | "winapi-util", 727 | ] 728 | 729 | [[package]] 730 | name = "quote" 731 | version = "1.0.37" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 734 | dependencies = [ 735 | "proc-macro2", 736 | ] 737 | 738 | [[package]] 739 | name = "rand" 740 | version = "0.8.5" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 743 | dependencies = [ 744 | "libc", 745 | "rand_chacha", 746 | "rand_core", 747 | ] 748 | 749 | [[package]] 750 | name = "rand_chacha" 751 | version = "0.3.1" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 754 | dependencies = [ 755 | "ppv-lite86", 756 | "rand_core", 757 | ] 758 | 759 | [[package]] 760 | name = "rand_core" 761 | version = "0.6.4" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 764 | dependencies = [ 765 | "getrandom", 766 | ] 767 | 768 | [[package]] 769 | name = "regex" 770 | version = "1.11.1" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 773 | dependencies = [ 774 | "aho-corasick", 775 | "memchr", 776 | "regex-automata", 777 | "regex-syntax", 778 | ] 779 | 780 | [[package]] 781 | name = "regex-automata" 782 | version = "0.4.9" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 785 | dependencies = [ 786 | "aho-corasick", 787 | "memchr", 788 | "regex-syntax", 789 | ] 790 | 791 | [[package]] 792 | name = "regex-syntax" 793 | version = "0.8.5" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 796 | 797 | [[package]] 798 | name = "rustix" 799 | version = "0.38.40" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" 802 | dependencies = [ 803 | "bitflags", 804 | "errno", 805 | "libc", 806 | "linux-raw-sys", 807 | "windows-sys 0.52.0", 808 | ] 809 | 810 | [[package]] 811 | name = "ryu" 812 | version = "1.0.18" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 815 | 816 | [[package]] 817 | name = "same-file" 818 | version = "1.0.6" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 821 | dependencies = [ 822 | "winapi-util", 823 | ] 824 | 825 | [[package]] 826 | name = "serde" 827 | version = "1.0.215" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 830 | dependencies = [ 831 | "serde_derive", 832 | ] 833 | 834 | [[package]] 835 | name = "serde_derive" 836 | version = "1.0.215" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 839 | dependencies = [ 840 | "proc-macro2", 841 | "quote", 842 | "syn", 843 | ] 844 | 845 | [[package]] 846 | name = "serde_json" 847 | version = "1.0.132" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" 850 | dependencies = [ 851 | "itoa", 852 | "memchr", 853 | "ryu", 854 | "serde", 855 | ] 856 | 857 | [[package]] 858 | name = "serde_spanned" 859 | version = "0.6.8" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 862 | dependencies = [ 863 | "serde", 864 | ] 865 | 866 | [[package]] 867 | name = "sha2" 868 | version = "0.10.8" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 871 | dependencies = [ 872 | "cfg-if", 873 | "cpufeatures", 874 | "digest", 875 | ] 876 | 877 | [[package]] 878 | name = "shlex" 879 | version = "1.3.0" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 882 | 883 | [[package]] 884 | name = "siphasher" 885 | version = "0.3.11" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 888 | 889 | [[package]] 890 | name = "slug" 891 | version = "0.1.6" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" 894 | dependencies = [ 895 | "deunicode", 896 | "wasm-bindgen", 897 | ] 898 | 899 | [[package]] 900 | name = "strsim" 901 | version = "0.11.1" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 904 | 905 | [[package]] 906 | name = "syn" 907 | version = "2.0.87" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 910 | dependencies = [ 911 | "proc-macro2", 912 | "quote", 913 | "unicode-ident", 914 | ] 915 | 916 | [[package]] 917 | name = "tempfile" 918 | version = "3.14.0" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" 921 | dependencies = [ 922 | "cfg-if", 923 | "fastrand", 924 | "once_cell", 925 | "rustix", 926 | "windows-sys 0.59.0", 927 | ] 928 | 929 | [[package]] 930 | name = "tera" 931 | version = "1.20.0" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" 934 | dependencies = [ 935 | "chrono", 936 | "chrono-tz", 937 | "globwalk", 938 | "humansize", 939 | "lazy_static", 940 | "percent-encoding", 941 | "pest", 942 | "pest_derive", 943 | "rand", 944 | "regex", 945 | "serde", 946 | "serde_json", 947 | "slug", 948 | "unic-segment", 949 | ] 950 | 951 | [[package]] 952 | name = "thiserror" 953 | version = "1.0.69" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 956 | dependencies = [ 957 | "thiserror-impl", 958 | ] 959 | 960 | [[package]] 961 | name = "thiserror-impl" 962 | version = "1.0.69" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 965 | dependencies = [ 966 | "proc-macro2", 967 | "quote", 968 | "syn", 969 | ] 970 | 971 | [[package]] 972 | name = "toml" 973 | version = "0.8.19" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 976 | dependencies = [ 977 | "serde", 978 | "serde_spanned", 979 | "toml_datetime", 980 | "toml_edit", 981 | ] 982 | 983 | [[package]] 984 | name = "toml_datetime" 985 | version = "0.6.8" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 988 | dependencies = [ 989 | "serde", 990 | ] 991 | 992 | [[package]] 993 | name = "toml_edit" 994 | version = "0.22.22" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 997 | dependencies = [ 998 | "indexmap", 999 | "serde", 1000 | "serde_spanned", 1001 | "toml_datetime", 1002 | "winnow", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "typenum" 1007 | version = "1.17.0" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1010 | 1011 | [[package]] 1012 | name = "ucd-trie" 1013 | version = "0.1.7" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" 1016 | 1017 | [[package]] 1018 | name = "unic-char-property" 1019 | version = "0.9.0" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" 1022 | dependencies = [ 1023 | "unic-char-range", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "unic-char-range" 1028 | version = "0.9.0" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" 1031 | 1032 | [[package]] 1033 | name = "unic-common" 1034 | version = "0.9.0" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" 1037 | 1038 | [[package]] 1039 | name = "unic-segment" 1040 | version = "0.9.0" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" 1043 | dependencies = [ 1044 | "unic-ucd-segment", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "unic-ucd-segment" 1049 | version = "0.9.0" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" 1052 | dependencies = [ 1053 | "unic-char-property", 1054 | "unic-char-range", 1055 | "unic-ucd-version", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "unic-ucd-version" 1060 | version = "0.9.0" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" 1063 | dependencies = [ 1064 | "unic-common", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "unicase" 1069 | version = "2.8.0" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" 1072 | 1073 | [[package]] 1074 | name = "unicode-ident" 1075 | version = "1.0.13" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 1078 | 1079 | [[package]] 1080 | name = "unicode-width" 1081 | version = "0.1.14" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1084 | 1085 | [[package]] 1086 | name = "unicode-width" 1087 | version = "0.2.0" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 1090 | 1091 | [[package]] 1092 | name = "utf8parse" 1093 | version = "0.2.2" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1096 | 1097 | [[package]] 1098 | name = "version_check" 1099 | version = "0.9.5" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1102 | 1103 | [[package]] 1104 | name = "walkdir" 1105 | version = "2.5.0" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1108 | dependencies = [ 1109 | "same-file", 1110 | "winapi-util", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "wasi" 1115 | version = "0.11.0+wasi-snapshot-preview1" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1118 | 1119 | [[package]] 1120 | name = "wasm-bindgen" 1121 | version = "0.2.95" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" 1124 | dependencies = [ 1125 | "cfg-if", 1126 | "once_cell", 1127 | "wasm-bindgen-macro", 1128 | ] 1129 | 1130 | [[package]] 1131 | name = "wasm-bindgen-backend" 1132 | version = "0.2.95" 1133 | source = "registry+https://github.com/rust-lang/crates.io-index" 1134 | checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" 1135 | dependencies = [ 1136 | "bumpalo", 1137 | "log", 1138 | "once_cell", 1139 | "proc-macro2", 1140 | "quote", 1141 | "syn", 1142 | "wasm-bindgen-shared", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "wasm-bindgen-macro" 1147 | version = "0.2.95" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" 1150 | dependencies = [ 1151 | "quote", 1152 | "wasm-bindgen-macro-support", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "wasm-bindgen-macro-support" 1157 | version = "0.2.95" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" 1160 | dependencies = [ 1161 | "proc-macro2", 1162 | "quote", 1163 | "syn", 1164 | "wasm-bindgen-backend", 1165 | "wasm-bindgen-shared", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "wasm-bindgen-shared" 1170 | version = "0.2.95" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" 1173 | 1174 | [[package]] 1175 | name = "web-time" 1176 | version = "1.1.0" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 1179 | dependencies = [ 1180 | "js-sys", 1181 | "wasm-bindgen", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "winapi-util" 1186 | version = "0.1.9" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1189 | dependencies = [ 1190 | "windows-sys 0.59.0", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "windows-core" 1195 | version = "0.52.0" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1198 | dependencies = [ 1199 | "windows-targets", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "windows-sys" 1204 | version = "0.52.0" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1207 | dependencies = [ 1208 | "windows-targets", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "windows-sys" 1213 | version = "0.59.0" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1216 | dependencies = [ 1217 | "windows-targets", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "windows-targets" 1222 | version = "0.52.6" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1225 | dependencies = [ 1226 | "windows_aarch64_gnullvm", 1227 | "windows_aarch64_msvc", 1228 | "windows_i686_gnu", 1229 | "windows_i686_gnullvm", 1230 | "windows_i686_msvc", 1231 | "windows_x86_64_gnu", 1232 | "windows_x86_64_gnullvm", 1233 | "windows_x86_64_msvc", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "windows_aarch64_gnullvm" 1238 | version = "0.52.6" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1241 | 1242 | [[package]] 1243 | name = "windows_aarch64_msvc" 1244 | version = "0.52.6" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1247 | 1248 | [[package]] 1249 | name = "windows_i686_gnu" 1250 | version = "0.52.6" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1253 | 1254 | [[package]] 1255 | name = "windows_i686_gnullvm" 1256 | version = "0.52.6" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1259 | 1260 | [[package]] 1261 | name = "windows_i686_msvc" 1262 | version = "0.52.6" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1265 | 1266 | [[package]] 1267 | name = "windows_x86_64_gnu" 1268 | version = "0.52.6" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1271 | 1272 | [[package]] 1273 | name = "windows_x86_64_gnullvm" 1274 | version = "0.52.6" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1277 | 1278 | [[package]] 1279 | name = "windows_x86_64_msvc" 1280 | version = "0.52.6" 1281 | source = "registry+https://github.com/rust-lang/crates.io-index" 1282 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1283 | 1284 | [[package]] 1285 | name = "winnow" 1286 | version = "0.6.20" 1287 | source = "registry+https://github.com/rust-lang/crates.io-index" 1288 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 1289 | dependencies = [ 1290 | "memchr", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "zerocopy" 1295 | version = "0.7.35" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1298 | dependencies = [ 1299 | "byteorder", 1300 | "zerocopy-derive", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "zerocopy-derive" 1305 | version = "0.7.35" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1308 | dependencies = [ 1309 | "proc-macro2", 1310 | "quote", 1311 | "syn", 1312 | ] 1313 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cppdoc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.93" 10 | clang = "2.0.0" 11 | clap = { version = "4.5.21", features = ["derive"] } 12 | glob = "0.3.1" 13 | indicatif = "0.17.9" 14 | lazy_static = "1.5.0" 15 | pulldown-cmark = { version = "0.12.2", default-features = false, features = ["html"] } 16 | pygmentize = "0.2.0" 17 | serde = { version = "1.0.215", features = ["derive"] } 18 | serde_json = "1.0.132" 19 | tempfile = "3.14.0" 20 | tera = "1.20.0" 21 | toml = "0.8.19" 22 | 23 | [profile.release] 24 | lto = true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 rdmsr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cppdoc 2 | cppdoc is a C++ documentation generator inspired by `rustdoc` 3 | 4 | ## Features 5 | - `rustdoc`-like documentation comments, rendered using markdown 6 | - Documentation tests using codeblocks 7 | - Extra pages written in markdown 8 | - [Mermaid](https://mermaid.js.org) graphs 9 | - Flexible styling options with user-supplied stylesheets (see default themes in `example/`) 10 | - libclang-based parser with support for records, enums, functions and namespaces 11 | - Decent performance, with generation usually being faster than libclang-backed Doxygen 12 | 13 | ## Usage 14 | See [USAGE.md](USAGE.md) 15 | 16 | ## Preview 17 | There is a live demo available [here](https://rdmsr.github.io/cppdoc). 18 | 19 | Here is what cppdoc looks like with three different stylesheets: 20 | 21 | `example/static/light.css`: 22 | ![light preview](assets/light-preview.png) 23 | 24 | `example/static/ayu.css`: 25 | ![ayu preview](assets/ayu-preview.png) 26 | 27 | `example/static/gruvbox.css`: 28 | ![gruvbox preview](assets/gruvbox-preview.png) 29 | 30 | -------------------------------------------------------------------------------- /USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | Projects using `cppdoc` must have a `cppdoc.toml` configuration file, see [CONFIG.md](CONFIG.md) for the available configuration options. 3 | 4 | ## Command-line options: 5 | To build documentation for a project: 6 | 7 | ``` 8 | cppdoc build 9 | ``` 10 | 11 | To output JSON representing the codebase: 12 | 13 | ``` 14 | cppdoc build -d 15 | ``` 16 | 17 | More command-line options can be displayed using `-h` or `--help`. 18 | 19 | 20 | ## Comments 21 | Comments are written using `///` or `//<`, the latter being used for inline documentation, as such: 22 | 23 | ```cpp 24 | /// Documentation for 'MyEnum' 25 | enum MyEnum { 26 | A //< Documentation for 'A' 27 | } 28 | ``` 29 | 30 | Comments content are parsed as cppdoc-flavored markdown, there is no support for `javadoc`/Doxygen-style comments. 31 | 32 | ## Markdown syntax 33 | `cppdoc` introduces a few extensions to markdown. 34 | 35 | - To link documentation objects, one must prefix the link path with `::`. For example: 36 | 37 | ``` 38 | See [MyStruct](::MyStruct) 39 | ``` 40 | 41 | - Mermaid graphs can be displayed using `mermaid` codeblocks: 42 | 43 | ```mermaid 44 | graph TD; 45 | A-->B; 46 | A-->C; 47 | B-->D; 48 | C-->D; 49 | ``` 50 | 51 | ## Documentation tests 52 | `cppdoc` supports running documentation tests akin to `rustdoc`, these tests are written in `cpp` and `c++` codeblocks and help ensure that code examples are up-to-date with API usage. 53 | 54 | Documentation codeblocks feature special syntax: 55 | - Lines prefixed with `@` won't be displayed, but will be added to the source code: 56 | 57 | ``` 58 | @int a = 1; 59 | int b = a + 2; 60 | ``` 61 | 62 | Will only display: 63 | 64 | ``` 65 | int b = a + 2; 66 | ``` 67 | 68 | But will be compiled fully, that is with `int a = 1` included. 69 | 70 | 71 | - Similarly, `@include` allows for quiet inclusion of a header file: 72 | 73 | ``` 74 | @include "file.h" 75 | int a = 1; 76 | ``` 77 | 78 | Will only display: 79 | 80 | ``` 81 | int a = 1; 82 | ``` 83 | 84 | Notice that documentation tests don't need a `main` function, this is because documentation tests run by default in `main`. To disable this behavior one must set the codeblock language to `nomain` instead of `c++` or `cpp`. 85 | 86 | 87 | ### Test framework 88 | `cppdoc` includes a basic test framework for documentation tests, this is useful for testing that examples still run successfully. 89 | The following macros are defined: 90 | 91 | - `ASSERT` and `ASSERT_EQ`: test for truth and equality, respectively 92 | - `ASSERT_FALSE` and `ASSERT_NE`: test for falsity and inequality, respectively 93 | - `ASSERT_GT` and `ASSERT_LT`: test for greater than and less than, respectively 94 | - `ASSERT_GE` and `ASSERT_LE`: test for greater than or equal and less than or equal, respectively 95 | 96 | Therefore, it is possible to write code like so: 97 | 98 | ```c++ 99 | int a = 1; 100 | ASSERT(a == 1); 101 | ``` 102 | 103 | The code above will compile and run successfully, but the following code will fail to run: 104 | 105 | ```c++ 106 | int a = 2; 107 | ASSERT(a == 1); 108 | ``` 109 | 110 | 111 | # Styling 112 | `cppdoc` expects a `style.css` file to be present at the root of the generated documentation. It is recommended to put the stylesheets in a static directory and set the `static` option in the configuration file. 113 | -------------------------------------------------------------------------------- /assets/ayu-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdmsr/cppdoc/c8e5afdca3d08dfc56840c62e671b5a75ed573f9/assets/ayu-preview.png -------------------------------------------------------------------------------- /assets/gruvbox-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdmsr/cppdoc/c8e5afdca3d08dfc56840c62e671b5a75ed573f9/assets/gruvbox-preview.png -------------------------------------------------------------------------------- /assets/light-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdmsr/cppdoc/c8e5afdca3d08dfc56840c62e671b5a75ed573f9/assets/light-preview.png -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # This is an example documentation site generated by cppdoc 2 | 3 | syntax highlighting example: 4 | 5 | ```c++ 6 | #include 7 | 8 | int main() { 9 | std::cout << "hello, world!" << std::endl; 10 | return 0; 11 | } 12 | ``` 13 | 14 | Code references get appended to index files: 15 | -------------------------------------------------------------------------------- /example/cppdoc.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "Example" 3 | version = "0.1.0" 4 | 5 | [input] 6 | glob = "include/**/*.hpp" 7 | compiler_arguments = ["-Iinclude", "-std=gnu++20", "-xc++"] 8 | 9 | [pages] 10 | index = "README.md" 11 | extra = ["extra-pages/extra-page.md"] 12 | 13 | [output] 14 | static_dir = "static" 15 | path = "docs" 16 | base_url = "/cppdoc" 17 | 18 | [doctests] 19 | enable = false 20 | -------------------------------------------------------------------------------- /example/extra-pages/extra-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Extra Page 3 | --- 4 | # This is an Extra Page 5 | 6 | This is a graph generated by mermaid: 7 | 8 | ```mermaid 9 | --- 10 | config: 11 | look: handDrawn 12 | --- 13 | flowchart LR 14 | A[Start] --> B{Decision} 15 | B -->|Yes| C[Continue] 16 | B -->|No| D[Stop] 17 | ``` 18 | 19 | In Markdown, it is possible to link documentation objects: See [`MyStruct`](::MyStruct) 20 | 21 | See this too: [`OtherStruct`](::OtherStruct) 22 | -------------------------------------------------------------------------------- /example/include/file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// This is an example structure 4 | struct MyStruct { 5 | int a; 6 | }; 7 | 8 | /// This is another example structure used to demonstrate cross-references 9 | /// between types 10 | struct OtherStruct { 11 | /// Something 12 | MyStruct b; 13 | }; 14 | 15 | /// A function that does nothing 16 | /// - `a`: First parameter 17 | /// - `b`: Second parameter 18 | void function(int a, OtherStruct b); 19 | -------------------------------------------------------------------------------- /example/static/ayu.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap'); 2 | 3 | :root { 4 | --font-main: "Fira Sans", sans-serif; 5 | --font-secondary: "Source Serif 4", sans-serif; 6 | --font-code: "Source Code Pro", monospace; 7 | --font-scale: 1rem; 8 | --width: 1000px; 9 | --bg-color: #0F1419; 10 | --text-color: #E6E1CF; 11 | --heading-color: #E6E1CF; 12 | --link-color: #FF7733; 13 | --code-color: #E6E1CF; 14 | --code-bg-color: #191f26; 15 | --highlight-color: #E6B67330; 16 | } 17 | 18 | 19 | .highlight .hll { background-color: #ffffcc } 20 | .highlight { background: #191f26; color: #E6E1CF; background-color: #191f26 } 21 | .highlight .c { color: #5C6773; background-color: #191f26 } /* Comment */ 22 | .highlight .err { color: #E6E1CF; background-color: #191f26 } /* Error */ 23 | .highlight .esc { color: #E6E1CF; background-color: #191f26 } /* Escape */ 24 | .highlight .g { color: #E6E1CF; background-color: #191f26 } /* Generic */ 25 | .highlight .k { color: #FF7733; background-color: #191f26 } /* Keyword */ 26 | .highlight .l { color: #E6E1CF; background-color: #191f26 } /* Literal */ 27 | .highlight .n { color: #E6E1CF; background-color: #191f26 } /* Name */ 28 | .highlight .o { color: #E6E1CF; background-color: #191f26 } /* Operator */ 29 | .highlight .x { color: #E6E1CF; background-color: #191f26 } /* Other */ 30 | .highlight .p { color: #E6E1CF; background-color: #191f26 } /* Punctuation */ 31 | .highlight .ch { color: #5C6773; background-color: #191f26 } /* Comment.Hashbang */ 32 | .highlight .cm { color: #5C6773; background-color: #191f26 } /* Comment.Multiline */ 33 | .highlight .cp { color: #E6B673; background-color: #191f26 } /* Comment.Preproc */ 34 | .highlight .cpf { color: #5C6773; background-color: #191f26 } /* Comment.PreprocFile */ 35 | .highlight .c1 { color: #5C6773; background-color: #191f26 } /* Comment.Single */ 36 | .highlight .cs { color: #5C6773; background-color: #191f26 } /* Comment.Special */ 37 | .highlight .gd { color: #8a2be2; font-weight: bold; background-color: #e0ffff } /* Generic.Deleted */ 38 | .highlight .ge { color: #36A3D9; text-decoration: underline; background-color: #191f26 } /* Generic.Emph */ 39 | .highlight .gr { color: #E6E1CF; background-color: #FF3333 } /* Generic.Error */ 40 | .highlight .gh { color: #FF7733; background-color: #191f26 } /* Generic.Heading */ 41 | .highlight .gi { color: #B8CC52; background-color: #14191F } /* Generic.Inserted */ 42 | .highlight .go { color: #2D3640; background-color: #191f26 } /* Generic.Output */ 43 | .highlight .gp { color: #E6E1CF; background-color: #191f26 } /* Generic.Prompt */ 44 | .highlight .gs { color: #E6E1CF; background-color: #191f26 } /* Generic.Strong */ 45 | .highlight .gu { color: #FF7733; background-color: #191f26 } /* Generic.Subheading */ 46 | .highlight .gt { color: #E6E1CF; background-color: #FF3333 } /* Generic.Traceback */ 47 | .highlight .kc { color: #FF7733; background-color: #191f26 } /* Keyword.Constant */ 48 | .highlight .kd { color: #FF7733; background-color: #191f26 } /* Keyword.Declaration */ 49 | .highlight .kn { color: #FF7733; background-color: #191f26 } /* Keyword.Namespace */ 50 | .highlight .kp { color: #FF7733; background-color: #191f26 } /* Keyword.Pseudo */ 51 | .highlight .kr { color: #FF7733; background-color: #191f26 } /* Keyword.Reserved */ 52 | .highlight .kt { color: #36A3D9; background-color: #191f26 } /* Keyword.Type */ 53 | .highlight .ld { color: #E6E1CF; background-color: #191f26 } /* Literal.Date */ 54 | .highlight .m { color: #E6E1CF; background-color: #191f26 } /* Literal.Number */ 55 | .highlight .s { color: #B8CC52; background-color: #191f26 } /* Literal.String */ 56 | .highlight .na { color: #FFB454; background-color: #191f26 } /* Name.Attribute */ 57 | .highlight .nb { color: #E6E1CF; background-color: #191f26 } /* Name.Builtin */ 58 | .highlight .nc { color: #E6E1CF; background-color: #191f26 } /* Name.Class */ 59 | .highlight .no { color: #FFEE99; background-color: #191f26 } /* Name.Constant */ 60 | .highlight .nd { color: #E6E1CF; background-color: #191f26 } /* Name.Decorator */ 61 | .highlight .ni { color: #E6B673; background-color: #191f26 } /* Name.Entity */ 62 | .highlight .ne { color: #E6E1CF; background-color: #191f26 } /* Name.Exception */ 63 | .highlight .nf { color: #FFB454; background-color: #191f26 } /* Name.Function */ 64 | .highlight .nl { color: #E6E1CF; background-color: #191f26 } /* Name.Label */ 65 | .highlight .nn { color: #E6E1CF; background-color: #191f26 } /* Name.Namespace */ 66 | .highlight .nx { color: #E6E1CF; background-color: #191f26 } /* Name.Other */ 67 | .highlight .py { color: #E6E1CF; background-color: #191f26 } /* Name.Property */ 68 | .highlight .nt { color: #FF7733; background-color: #191f26 } /* Name.Tag */ 69 | .highlight .nv { color: #36A3D9; background-color: #191f26 } /* Name.Variable */ 70 | .highlight .ow { color: #E7C547; background-color: #191f26 } /* Operator.Word */ 71 | .highlight .w { color: #E6E1CF; background-color: #191f26 } /* Text.Whitespace */ 72 | .highlight .mb { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Bin */ 73 | .highlight .mf { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Float */ 74 | .highlight .mh { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Hex */ 75 | .highlight .mi { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Integer */ 76 | .highlight .mo { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Oct */ 77 | .highlight .sa { color: #B8CC52; background-color: #191f26 } /* Literal.String.Affix */ 78 | .highlight .sb { color: #B8CC52; background-color: #191f26 } /* Literal.String.Backtick */ 79 | .highlight .sc { color: #B8CC52; background-color: #191f26 } /* Literal.String.Char */ 80 | .highlight .dl { color: #B8CC52; background-color: #191f26 } /* Literal.String.Delimiter */ 81 | .highlight .sd { color: #B8CC52; background-color: #191f26 } /* Literal.String.Doc */ 82 | .highlight .s2 { color: #B8CC52; background-color: #191f26 } /* Literal.String.Double */ 83 | .highlight .se { color: #B8CC52; background-color: #191f26 } /* Literal.String.Escape */ 84 | .highlight .sh { color: #B8CC52; background-color: #191f26 } /* Literal.String.Heredoc */ 85 | .highlight .si { color: #B8CC52; background-color: #191f26 } /* Literal.String.Interpol */ 86 | .highlight .sx { color: #B8CC52; background-color: #191f26 } /* Literal.String.Other */ 87 | .highlight .sr { color: #B8CC52; background-color: #191f26 } /* Literal.String.Regex */ 88 | .highlight .s1 { color: #B8CC52; background-color: #191f26 } /* Literal.String.Single */ 89 | .highlight .ss { color: #B8CC52; background-color: #191f26 } /* Literal.String.Symbol */ 90 | .highlight .bp { color: #E6E1CF; background-color: #191f26 } /* Name.Builtin.Pseudo */ 91 | .highlight .fm { color: #FFB454; background-color: #191f26 } /* Name.Function.Magic */ 92 | .highlight .vc { color: #36A3D9; background-color: #191f26 } /* Name.Variable.Class */ 93 | .highlight .vg { color: #36A3D9; background-color: #191f26 } /* Name.Variable.Global */ 94 | .highlight .vi { color: #36A3D9; background-color: #191f26 } /* Name.Variable.Instance */ 95 | .highlight .vm { color: #36A3D9; background-color: #191f26 } /* Name.Variable.Magic */ 96 | .highlight .il { color: #E6E1CF; background-color: #191f26 } /* Literal.Number.Integer.Long */ 97 | -------------------------------------------------------------------------------- /example/static/gruvbox.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap'); 2 | 3 | :root { 4 | --bg_h: #1d2021; 5 | --bg: #282828; 6 | --bg_s: #32302f; 7 | --bg1: #3c3836; 8 | --bg2: #504945; 9 | --bg3: #665c54; 10 | --bg4: #7c6f64; 11 | 12 | --fg: #fbf1c7; 13 | --fg1: #ebdbb2; 14 | --fg2: #d5c4a1; 15 | --fg3: #bdae93; 16 | --fg4: #a89984; 17 | 18 | --red: #fb4934; 19 | --green: #b8bb26; 20 | --yellow: #fabd2f; 21 | --blue: #83a598; 22 | --purple: #d3869b; 23 | --aqua: #8ec07c; 24 | --gray: #928374; 25 | --orange: #fe8019; 26 | 27 | --red-dim: #cc2412; 28 | --green-dim: #98971a; 29 | --yellow-dim: #d79921; 30 | --blue-dim: #458588; 31 | --purple-dim: #b16286; 32 | --aqua-dim: #689d6a; 33 | --gray-dim: #a89984; 34 | --orange-dim: #d65d0e; 35 | --font-main: "Fira Sans", sans-serif; 36 | --font-secondary: "Source Serif 4", sans-serif; 37 | --font-code: "Source Code Pro", monospace; 38 | --font-scale: 1rem; 39 | --width: 1000px; 40 | --bg-color: var(--bg_s); 41 | --text-color: var(--fg); 42 | --heading-color: var(--fg1); 43 | --link-color: var(--orange); 44 | --code-color: var(--fg1); 45 | --code-bg-color: var(--bg); 46 | --highlight-color: var(--bg2); 47 | } 48 | 49 | .highlight .hll { background-color: #ebdbb2 } 50 | .highlight { background: #282828; color: #dddddd } 51 | .highlight .c { color: #928374; font-style: italic } /* Comment */ 52 | .highlight .err { color: #282828; background-color: #fb4934 } /* Error */ 53 | .highlight .esc { color: #dddddd } /* Escape */ 54 | .highlight .g { color: #dddddd } /* Generic */ 55 | .highlight .k { color: #fb4934 } /* Keyword */ 56 | .highlight .l { color: #dddddd } /* Literal */ 57 | .highlight .n { color: #dddddd } /* Name */ 58 | .highlight .o { color: #dddddd } /* Operator */ 59 | .highlight .x { color: #dddddd } /* Other */ 60 | .highlight .p { color: #dddddd } /* Punctuation */ 61 | .highlight .ch { color: #928374; font-style: italic } /* Comment.Hashbang */ 62 | .highlight .cm { color: #928374; font-style: italic } /* Comment.Multiline */ 63 | .highlight .c-PreProc { color: #8ec07c; font-style: italic } /* Comment.PreProc */ 64 | .highlight .cp { color: #928374; font-style: italic } /* Comment.Preproc */ 65 | .highlight .cpf { color: #928374; font-style: italic } /* Comment.PreprocFile */ 66 | .highlight .c1 { color: #928374; font-style: italic } /* Comment.Single */ 67 | .highlight .cs { color: #ebdbb2; font-weight: bold; font-style: italic } /* Comment.Special */ 68 | .highlight .gd { color: #282828; background-color: #fb4934 } /* Generic.Deleted */ 69 | .highlight .ge { color: #dddddd; font-style: italic } /* Generic.Emph */ 70 | .highlight .ges { color: #dddddd; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ 71 | .highlight .gr { color: #fb4934 } /* Generic.Error */ 72 | .highlight .gh { color: #ebdbb2; font-weight: bold } /* Generic.Heading */ 73 | .highlight .gi { color: #282828; background-color: #b8bb26 } /* Generic.Inserted */ 74 | .highlight .go { color: #f2e5bc } /* Generic.Output */ 75 | .highlight .gp { color: #a89984 } /* Generic.Prompt */ 76 | .highlight .gs { color: #dddddd; font-weight: bold } /* Generic.Strong */ 77 | .highlight .gu { color: #ebdbb2; text-decoration: underline } /* Generic.Subheading */ 78 | .highlight .gt { color: #fb4934 } /* Generic.Traceback */ 79 | .highlight .kc { color: #fb4934 } /* Keyword.Constant */ 80 | .highlight .kd { color: #fb4934 } /* Keyword.Declaration */ 81 | .highlight .kn { color: #fb4934 } /* Keyword.Namespace */ 82 | .highlight .kp { color: #fb4934 } /* Keyword.Pseudo */ 83 | .highlight .kr { color: #fb4934 } /* Keyword.Reserved */ 84 | .highlight .kt { color: #fb4934 } /* Keyword.Type */ 85 | .highlight .ld { color: #dddddd } /* Literal.Date */ 86 | .highlight .m { color: #d3869b } /* Literal.Number */ 87 | .highlight .s { color: #b8bb26 } /* Literal.String */ 88 | .highlight .na { color: #fabd2f } /* Name.Attribute */ 89 | .highlight .nb { color: #fe8019 } /* Name.Builtin */ 90 | .highlight .nc { color: #8ec07c } /* Name.Class */ 91 | .highlight .no { color: #d3869b } /* Name.Constant */ 92 | .highlight .nd { color: #fb4934 } /* Name.Decorator */ 93 | .highlight .ni { color: #dddddd } /* Name.Entity */ 94 | .highlight .ne { color: #fb4934 } /* Name.Exception */ 95 | .highlight .nf { color: #8ec07c } /* Name.Function */ 96 | .highlight .nl { color: #dddddd } /* Name.Label */ 97 | .highlight .nn { color: #8ec07c } /* Name.Namespace */ 98 | .highlight .nx { color: #dddddd } /* Name.Other */ 99 | .highlight .py { color: #dddddd } /* Name.Property */ 100 | .highlight .nt { color: #8ec07c } /* Name.Tag */ 101 | .highlight .nv { color: #83a598 } /* Name.Variable */ 102 | .highlight .ow { color: #fb4934 } /* Operator.Word */ 103 | .highlight .pm { color: #dddddd } /* Punctuation.Marker */ 104 | .highlight .w { color: #dddddd } /* Text.Whitespace */ 105 | .highlight .mb { color: #d3869b } /* Literal.Number.Bin */ 106 | .highlight .mf { color: #d3869b } /* Literal.Number.Float */ 107 | .highlight .mh { color: #d3869b } /* Literal.Number.Hex */ 108 | .highlight .mi { color: #d3869b } /* Literal.Number.Integer */ 109 | .highlight .mo { color: #d3869b } /* Literal.Number.Oct */ 110 | .highlight .sa { color: #b8bb26 } /* Literal.String.Affix */ 111 | .highlight .sb { color: #b8bb26 } /* Literal.String.Backtick */ 112 | .highlight .sc { color: #b8bb26 } /* Literal.String.Char */ 113 | .highlight .dl { color: #b8bb26 } /* Literal.String.Delimiter */ 114 | .highlight .sd { color: #b8bb26 } /* Literal.String.Doc */ 115 | .highlight .s2 { color: #b8bb26 } /* Literal.String.Double */ 116 | .highlight .se { color: #fe8019 } /* Literal.String.Escape */ 117 | .highlight .sh { color: #b8bb26 } /* Literal.String.Heredoc */ 118 | .highlight .si { color: #b8bb26 } /* Literal.String.Interpol */ 119 | .highlight .sx { color: #b8bb26 } /* Literal.String.Other */ 120 | .highlight .sr { color: #b8bb26 } /* Literal.String.Regex */ 121 | .highlight .s1 { color: #b8bb26 } /* Literal.String.Single */ 122 | .highlight .ss { color: #b8bb26 } /* Literal.String.Symbol */ 123 | .highlight .bp { color: #fe8019 } /* Name.Builtin.Pseudo */ 124 | .highlight .fm { color: #8ec07c } /* Name.Function.Magic */ 125 | .highlight .vc { color: #83a598 } /* Name.Variable.Class */ 126 | .highlight .vg { color: #83a598 } /* Name.Variable.Global */ 127 | .highlight .vi { color: #83a598 } /* Name.Variable.Instance */ 128 | .highlight .vm { color: #83a598 } /* Name.Variable.Magic */ 129 | .highlight .il { color: #d3869b } /* Literal.Number.Integer.Long */ 130 | -------------------------------------------------------------------------------- /example/static/light.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap'); 2 | 3 | :root { 4 | --font-main: "Georgia", serif; 5 | --font-secondary: "Georgia", serif; 6 | --font-code: "Source Code Pro", monospace; 7 | --font-scale: 1rem; 8 | --width: 1000px; 9 | --bg-color: white; 10 | --text-color: #3E4349; 11 | --heading-color: #3E4349; 12 | --link-color: #004B6B; 13 | --highlight-color: #E6B67330; 14 | } 15 | 16 | .highlight .hll { background-color: #ffffcc } 17 | .highlight { background: #f8f8f8; } 18 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ 19 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 20 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */ 21 | .highlight .o { color: #666666 } /* Operator */ 22 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ 23 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ 24 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */ 25 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ 26 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ 27 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ 28 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 29 | .highlight .ge { font-style: italic } /* Generic.Emph */ 30 | .highlight .gr { color: #E40000 } /* Generic.Error */ 31 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 32 | .highlight .gi { color: #008400 } /* Generic.Inserted */ 33 | .highlight .go { color: #717171 } /* Generic.Output */ 34 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 35 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 36 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 37 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 38 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 39 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 40 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 41 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */ 42 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 43 | .highlight .kt { color: #B00040 } /* Keyword.Type */ 44 | .highlight .m { color: #666666 } /* Literal.Number */ 45 | .highlight .s { color: #BA2121 } /* Literal.String */ 46 | .highlight .na { color: #687822 } /* Name.Attribute */ 47 | .highlight .nb { color: #008000 } /* Name.Builtin */ 48 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 49 | .highlight .no { color: #880000 } /* Name.Constant */ 50 | .highlight .nd { color: #AA22FF } /* Name.Decorator */ 51 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ 52 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ 53 | .highlight .nf { color: #0000FF } /* Name.Function */ 54 | .highlight .nl { color: #767600 } /* Name.Label */ 55 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 56 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ 57 | .highlight .nv { color: #19177C } /* Name.Variable */ 58 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 59 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 60 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */ 61 | .highlight .mf { color: #666666 } /* Literal.Number.Float */ 62 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */ 63 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */ 64 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */ 65 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */ 66 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ 67 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */ 68 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ 69 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 70 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ 71 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ 72 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ 73 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ 74 | .highlight .sx { color: #008000 } /* Literal.String.Other */ 75 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */ 76 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ 77 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */ 78 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ 79 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */ 80 | .highlight .vc { color: #19177C } /* Name.Variable.Class */ 81 | .highlight .vg { color: #19177C } /* Name.Variable.Global */ 82 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */ 83 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */ 84 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /example/static/onedark.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap'); 2 | 3 | :root { 4 | --font-main: "Fira Sans", sans-serif; 5 | --font-secondary: "Source Serif 4", sans-serif; 6 | --font-code: "Source Code Pro", monospace; 7 | --font-scale: 1rem; 8 | --width: 1000px; 9 | --bg-color: #282c34; 10 | --text-color: #ABB2BF; 11 | --heading-color: #ABB2BF; 12 | --link-color: #56B6C2; 13 | --code-color: #ABB2BF; 14 | --code-bg-color: #1f2329; 15 | --highlight-color: #E6B67330; 16 | } 17 | 18 | .highlight .hll { background-color: #ffffcc } 19 | .highlight { background: #1f2329; color: #ABB2BF } 20 | .highlight .c { color: #7F848E } /* Comment */ 21 | .highlight .err { color: #ABB2BF } /* Error */ 22 | .highlight .esc { color: #ABB2BF } /* Escape */ 23 | .highlight .g { color: #ABB2BF } /* Generic */ 24 | .highlight .k { color: #C678DD } /* Keyword */ 25 | .highlight .l { color: #ABB2BF } /* Literal */ 26 | .highlight .n { color: #E06C75 } /* Name */ 27 | .highlight .o { color: #56B6C2 } /* Operator */ 28 | .highlight .x { color: #ABB2BF } /* Other */ 29 | .highlight .p { color: #ABB2BF } /* Punctuation */ 30 | .highlight .ch { color: #7F848E } /* Comment.Hashbang */ 31 | .highlight .cm { color: #7F848E } /* Comment.Multiline */ 32 | .highlight .cp { color: #7F848E } /* Comment.Preproc */ 33 | .highlight .cpf { color: #7F848E } /* Comment.PreprocFile */ 34 | .highlight .c1 { color: #7F848E } /* Comment.Single */ 35 | .highlight .cs { color: #7F848E } /* Comment.Special */ 36 | .highlight .gd { color: #ABB2BF } /* Generic.Deleted */ 37 | .highlight .ge { color: #ABB2BF } /* Generic.Emph */ 38 | .highlight .gr { color: #ABB2BF } /* Generic.Error */ 39 | .highlight .gh { color: #ABB2BF } /* Generic.Heading */ 40 | .highlight .gi { color: #ABB2BF } /* Generic.Inserted */ 41 | .highlight .go { color: #ABB2BF } /* Generic.Output */ 42 | .highlight .gp { color: #ABB2BF } /* Generic.Prompt */ 43 | .highlight .gs { color: #ABB2BF } /* Generic.Strong */ 44 | .highlight .gu { color: #ABB2BF } /* Generic.Subheading */ 45 | .highlight .gt { color: #ABB2BF } /* Generic.Traceback */ 46 | .highlight .kc { color: #E5C07B } /* Keyword.Constant */ 47 | .highlight .kd { color: #C678DD } /* Keyword.Declaration */ 48 | .highlight .kn { color: #C678DD } /* Keyword.Namespace */ 49 | .highlight .kp { color: #C678DD } /* Keyword.Pseudo */ 50 | .highlight .kr { color: #C678DD } /* Keyword.Reserved */ 51 | .highlight .kt { color: #E5C07B } /* Keyword.Type */ 52 | .highlight .ld { color: #ABB2BF } /* Literal.Date */ 53 | .highlight .m { color: #D19A66 } /* Literal.Number */ 54 | .highlight .s { color: #98C379 } /* Literal.String */ 55 | .highlight .na { color: #E06C75 } /* Name.Attribute */ 56 | .highlight .nb { color: #E5C07B } /* Name.Builtin */ 57 | .highlight .nc { color: #E5C07B } /* Name.Class */ 58 | .highlight .no { color: #E06C75 } /* Name.Constant */ 59 | .highlight .nd { color: #61AFEF } /* Name.Decorator */ 60 | .highlight .ni { color: #E06C75 } /* Name.Entity */ 61 | .highlight .ne { color: #E06C75 } /* Name.Exception */ 62 | .highlight .nf { color: #61AFEF; font-weight: bold } /* Name.Function */ 63 | .highlight .nl { color: #E06C75 } /* Name.Label */ 64 | .highlight .nn { color: #E06C75 } /* Name.Namespace */ 65 | .highlight .nx { color: #E06C75 } /* Name.Other */ 66 | .highlight .py { color: #E06C75 } /* Name.Property */ 67 | .highlight .nt { color: #E06C75 } /* Name.Tag */ 68 | .highlight .nv { color: #E06C75 } /* Name.Variable */ 69 | .highlight .ow { color: #56B6C2 } /* Operator.Word */ 70 | .highlight .pm { color: #ABB2BF } /* Punctuation.Marker */ 71 | .highlight .w { color: #ABB2BF } /* Text.Whitespace */ 72 | .highlight .mb { color: #D19A66 } /* Literal.Number.Bin */ 73 | .highlight .mf { color: #D19A66 } /* Literal.Number.Float */ 74 | .highlight .mh { color: #D19A66 } /* Literal.Number.Hex */ 75 | .highlight .mi { color: #D19A66 } /* Literal.Number.Integer */ 76 | .highlight .mo { color: #D19A66 } /* Literal.Number.Oct */ 77 | .highlight .sa { color: #98C379 } /* Literal.String.Affix */ 78 | .highlight .sb { color: #98C379 } /* Literal.String.Backtick */ 79 | .highlight .sc { color: #98C379 } /* Literal.String.Char */ 80 | .highlight .dl { color: #98C379 } /* Literal.String.Delimiter */ 81 | .highlight .sd { color: #98C379 } /* Literal.String.Doc */ 82 | .highlight .s2 { color: #98C379 } /* Literal.String.Double */ 83 | .highlight .se { color: #98C379 } /* Literal.String.Escape */ 84 | .highlight .sh { color: #98C379 } /* Literal.String.Heredoc */ 85 | .highlight .si { color: #98C379 } /* Literal.String.Interpol */ 86 | .highlight .sx { color: #98C379 } /* Literal.String.Other */ 87 | .highlight .sr { color: #98C379 } /* Literal.String.Regex */ 88 | .highlight .s1 { color: #98C379 } /* Literal.String.Single */ 89 | .highlight .ss { color: #98C379 } /* Literal.String.Symbol */ 90 | .highlight .bp { color: #E5C07B } /* Name.Builtin.Pseudo */ 91 | .highlight .fm { color: #56B6C2; font-weight: bold } /* Name.Function.Magic */ 92 | .highlight .vc { color: #E06C75 } /* Name.Variable.Class */ 93 | .highlight .vg { color: #E06C75 } /* Name.Variable.Global */ 94 | .highlight .vi { color: #E06C75 } /* Name.Variable.Instance */ 95 | .highlight .vm { color: #E06C75 } /* Name.Variable.Magic */ 96 | .highlight .il { color: #D19A66 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /example/static/style.css: -------------------------------------------------------------------------------- 1 | @import "ayu.css"; 2 | 3 | body { 4 | font-family: var(--font-secondary); 5 | font-size: var(--font-scale); 6 | margin: 0 auto; 7 | margin-left: 25%; 8 | padding: 20px; 9 | width: var(--width); 10 | max-width: 100%; 11 | text-align: left; 12 | background-color: var(--bg-color); 13 | word-wrap: break-word; 14 | overflow-wrap: break-word; 15 | overflow-x: hidden; 16 | line-height: 1.8; 17 | color: var(--text-color); 18 | } 19 | 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | h5, 25 | h6 { 26 | font-family: var(--font-main); 27 | color: var(--heading-color); 28 | border-bottom: 1px solid var(--text-color); 29 | } 30 | 31 | .namespace-link { 32 | border-bottom: 0; 33 | line-height: 1; 34 | font-family: var(--font-main); 35 | } 36 | 37 | a { 38 | color: var(--link-color); 39 | cursor: pointer; 40 | text-decoration: none; 41 | } 42 | 43 | nav a { 44 | margin-right: 8px; 45 | } 46 | 47 | strong, 48 | b { 49 | color: var(--heading-color); 50 | } 51 | 52 | button { 53 | margin: 0; 54 | cursor: pointer; 55 | } 56 | 57 | main { 58 | line-height: 1.6; 59 | } 60 | 61 | table { 62 | width: 100%; 63 | } 64 | 65 | hr { 66 | border: 0; 67 | border-top: 1px dashed; 68 | } 69 | 70 | img { 71 | max-width: 100%; 72 | } 73 | 74 | .highlight pre { 75 | font-family: var(--font-code); 76 | } 77 | 78 | code { 79 | font-family: var(--font-code); 80 | padding: 2px; 81 | color: var(--code-color); 82 | border-radius: 3px; 83 | background-color: var(--code-bg-color); 84 | } 85 | 86 | .nobg, 87 | .nobg * { 88 | background-color: var(--bg-color) !important; 89 | padding: 0px !important; 90 | } 91 | 92 | 93 | footer { 94 | padding: 25px 0; 95 | text-align: center; 96 | } 97 | 98 | .item-table { 99 | list-style: none; 100 | margin: 0; 101 | padding: 0; 102 | } 103 | 104 | :target { 105 | background-color: var(--highlight-color); 106 | } 107 | 108 | 109 | .item-table li { 110 | display: flex; 111 | justify-content: space-between; 112 | } 113 | 114 | .item-name { 115 | font-family: var(--font-main); 116 | } 117 | 118 | 119 | a code { 120 | color: var(--link-color) !important; 121 | } 122 | 123 | .item-name .item-desc * { 124 | margin-left: auto; 125 | } 126 | 127 | .item-desc { 128 | margin-left: 20px; 129 | } 130 | 131 | .item-desc p { 132 | display: inline; 133 | } 134 | 135 | .highlight, 136 | .code { 137 | padding: 1px 15px; 138 | border-radius: 3px; 139 | margin-block-start: 1em; 140 | margin-block-end: 1em; 141 | width: calc(100%-2rem); 142 | overflow-x: auto; 143 | } 144 | 145 | div.sidebarwrapper { 146 | padding: 10px 5px 0 10px; 147 | } 148 | 149 | div.sidebar { 150 | float: left; 151 | width: 230px; 152 | margin-left: -30%; 153 | font-size: 90%; 154 | word-wrap: break-word; 155 | overflow-wrap: break-word; 156 | max-height: 100%; 157 | overflow-y: auto; 158 | } 159 | 160 | div.sidebar ul { 161 | list-style-type: none; 162 | padding: 0; 163 | } 164 | 165 | div.sidebar h1, 166 | div.sidebar h2, 167 | div.sidebar h3 { 168 | border-bottom: 0; 169 | line-height: 1.25rem; 170 | } 171 | 172 | div.sidebar a { 173 | font-size: 1rem; 174 | } 175 | 176 | .searchbar { 177 | font-family: var(--font-secondary); 178 | background-color: var(--bg-color); 179 | color: var(--text-color); 180 | border-width: 0.5px; 181 | border-color: var(--text-color); 182 | border-radius: 2px; 183 | } 184 | 185 | @media (max-width: 1024px) { 186 | div.sidebar { 187 | float: none; 188 | width: 100%; 189 | margin-left: 0; 190 | max-height: none; 191 | } 192 | 193 | html, 194 | body { 195 | margin-left: 0px; 196 | overflow-x: hidden; 197 | -webkit-box-sizing: border-box; 198 | -moz-box-sizing: border-box; 199 | box-sizing: border-box; 200 | 201 | } 202 | 203 | /* Make search bar bigger so it's easier to tap on mobile */ 204 | .searchbar { 205 | width: 90%; 206 | font-size: 1.2rem; 207 | } 208 | 209 | .highlight, 210 | .code { 211 | width: calc(100%-10rem); 212 | } 213 | 214 | .item-table li { 215 | flex-direction: column; 216 | align-items: flex-start; 217 | } 218 | 219 | .item-name { 220 | flex: 0 0 auto; 221 | margin-bottom: 5px; 222 | } 223 | 224 | .item-table .item-desc * { 225 | margin-left: 20px; 226 | } 227 | } -------------------------------------------------------------------------------- /src/comment.rs: -------------------------------------------------------------------------------- 1 | use crate::parser::Comment; 2 | 3 | fn remove_prefix_and_clean(string: &str, prefix: &str) -> String { 4 | if let Some(stripped) = string.strip_prefix(prefix) { 5 | stripped.trim().to_string() 6 | } else { 7 | string.trim().to_string() 8 | } 9 | } 10 | 11 | pub fn parse_comment(string: String) -> Comment { 12 | let mut ret = Comment { 13 | brief: "".to_string(), 14 | description: "".to_string(), 15 | impl_: None, 16 | }; 17 | 18 | let mut lines = string.lines(); 19 | 20 | if let Some(line) = lines.next() { 21 | let trimmed = line.trim(); 22 | 23 | if trimmed.starts_with("///<") { 24 | ret.brief = remove_prefix_and_clean(trimmed, "///<"); 25 | } else { 26 | ret.brief = remove_prefix_and_clean(trimmed, "///"); 27 | } 28 | } 29 | 30 | let description = lines.fold(String::new(), |mut acc, line| { 31 | let cleaned_up = remove_prefix_and_clean(line.trim(), "///"); 32 | 33 | if cleaned_up.starts_with("\\impl{") { 34 | let impl_ = cleaned_up 35 | .trim_start_matches("\\impl{") 36 | .trim_end_matches('}') 37 | .split(',') 38 | .map(|s| s.trim().to_string()) 39 | .collect(); 40 | ret.impl_ = Some(impl_); 41 | return acc; 42 | } 43 | 44 | acc.push_str(&cleaned_up); 45 | acc.push('\n'); 46 | acc 47 | }); 48 | 49 | ret.description = description.trim().to_string(); 50 | 51 | ret 52 | } 53 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, Serialize, Clone, Debug)] 5 | pub struct Config { 6 | pub project: Project, 7 | pub input: Input, 8 | pub pages: Pages, 9 | pub output: Output, 10 | pub doctests: Option, 11 | } 12 | 13 | #[derive(Deserialize, Serialize, Clone, Debug)] 14 | pub struct Project { 15 | pub name: String, 16 | pub version: String, 17 | } 18 | 19 | #[derive(Deserialize, Serialize, Clone, Debug)] 20 | pub struct Input { 21 | pub glob: String, 22 | pub compiler_arguments: Vec, 23 | } 24 | 25 | #[derive(Deserialize, Serialize, Clone, Debug)] 26 | pub struct Pages { 27 | pub index: Option, 28 | pub extra: Option>, 29 | } 30 | 31 | #[derive(Deserialize, Serialize, Clone, Debug)] 32 | pub struct Output { 33 | pub static_dir: String, 34 | pub path: String, 35 | pub root_namespace: Option, 36 | pub base_url: String, 37 | } 38 | 39 | #[derive(Deserialize, Serialize, Clone, Debug)] 40 | pub struct Doctest { 41 | pub enable: bool, 42 | pub run: Option, 43 | pub compiler_invocation: Option>, 44 | } 45 | 46 | impl Config { 47 | pub fn new(config_file: &str) -> Result { 48 | let config_str = std::fs::read_to_string(config_file)?; 49 | 50 | let config: Config = toml::from_str(&config_str)?; 51 | Ok(config) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/doctest.rs: -------------------------------------------------------------------------------- 1 | use crate::config; 2 | use crate::report::report_error; 3 | use std::io::Write; 4 | use tempfile::NamedTempFile; 5 | 6 | pub struct Doctest { 7 | pub code: String, 8 | pub add_main: bool, 9 | pub include: Vec, 10 | pub display_code: String, 11 | } 12 | 13 | const PREPENDED_CODE: &str = r#" 14 | #include 15 | #include 16 | 17 | #ifdef ASSERT 18 | #undef ASSERT 19 | #endif 20 | 21 | #define ASSERT_EQ(A, B) if (A != B) { std::cerr << "Assertion failed: '" << #A << "' != '"<< #B << "'" << std::endl; exit(1); } 22 | #define ASSERT_NE(A, B) if (A == B) { std::cerr << "Assertion failed: '" << #A << "' == '"<< #B << "'" << std::endl; exit(1); } 23 | #define ASSERT_FALSE(A) if (A) { std::cerr << "Assertion failed: '" << #A << "' is true" << std::endl; exit(1); } 24 | #define ASSERT_GT(A, B) if (A <= B) { std::cerr << "Assertion failed: '" << #A << "' <= '"<< #B << "'" << std::endl; exit(1); } 25 | #define ASSERT_LT(A, B) if (A >= B) { std::cerr << "Assertion failed: '" << #A << "' >= '"<< #B << "'" << std::endl; exit(1); } 26 | #define ASSERT_GE(A, B) if (A < B) { std::cerr << "Assertion failed: '" << #A << "' < '"<< #B << "'" << std::endl; exit(1); } 27 | #define ASSERT_LE(A, B) if (A > B) { std::cerr << "Assertion failed: '" << #A << "' > '"<< #B << "'" << std::endl; exit(1); } 28 | 29 | #define ASSERT(A) if (!(A)) { std::cerr << "Assertion failed: '" << #A << "' is false" << std::endl; exit(1); } 30 | "#; 31 | 32 | impl Doctest { 33 | pub fn new(code: String, add_main: bool) -> Self { 34 | let mut full_code = String::new(); 35 | let mut display_code = String::new(); 36 | let mut include: Vec = Vec::new(); 37 | 38 | for line in code.lines() { 39 | if line.trim().starts_with("@") { 40 | if line.trim().starts_with("@include") { 41 | include.push(line.trim_start_matches("@include").trim().to_string()); 42 | } else { 43 | full_code.push_str(line.trim_start_matches("@")); 44 | full_code.push('\n'); 45 | } 46 | } else { 47 | display_code.push_str(line); 48 | display_code.push('\n'); 49 | 50 | full_code.push_str(line); 51 | full_code.push('\n'); 52 | } 53 | } 54 | 55 | Doctest { 56 | code: full_code, 57 | add_main, 58 | include, 59 | display_code, 60 | } 61 | } 62 | 63 | pub fn compile(&self, config: &config::Doctest) -> std::path::PathBuf { 64 | // This is fine, this should never panic 65 | let compiler_invocation = config.compiler_invocation.clone().unwrap(); 66 | let compiler_invocation = compiler_invocation.join(" "); 67 | 68 | let mut in_file = tempfile::Builder::new().suffix(".cpp").tempfile().unwrap(); 69 | 70 | let out_file = NamedTempFile::new().unwrap(); 71 | 72 | let compiler_invocation = 73 | compiler_invocation.replace("{file}", in_file.path().to_str().unwrap()); 74 | 75 | let compiler_invocation = 76 | compiler_invocation.replace("{out}", out_file.path().to_str().unwrap()); 77 | 78 | let mut command = std::process::Command::new("sh"); 79 | command.arg("-c").arg(&compiler_invocation); 80 | 81 | let orig_code = self.code.to_string(); 82 | 83 | if self.add_main { 84 | let includes = self 85 | .include 86 | .iter() 87 | .map(|i| format!("#include {}", i)) 88 | .collect::>() 89 | .join("\n"); 90 | 91 | let code = format!( 92 | "{}{}\nint main() {{\n{}\n return 0;}}", 93 | includes, PREPENDED_CODE, orig_code 94 | ); 95 | in_file.write_all(code.as_bytes()).unwrap(); 96 | } else { 97 | let includes = self 98 | .include 99 | .iter() 100 | .map(|i| format!("#include {}", i)) 101 | .collect::>() 102 | .join("\n"); 103 | 104 | let code = format!("{}{}{}", includes, PREPENDED_CODE, orig_code); 105 | in_file.write_all(code.as_bytes()).unwrap(); 106 | } 107 | 108 | let output = command.output().unwrap(); 109 | 110 | in_file.close().unwrap(); 111 | 112 | if !output.status.success() { 113 | report_error(&format!( 114 | "Could not compile test:\n{}\n\x1b[1mFull code:\x1b[0m\n{}", 115 | String::from_utf8_lossy(&output.stderr), 116 | orig_code 117 | )); 118 | std::process::exit(1); 119 | } 120 | 121 | out_file.keep().unwrap().1 122 | } 123 | 124 | pub fn run(&self, file_path: std::path::PathBuf) { 125 | let output = std::process::Command::new(file_path.clone()) 126 | .output() 127 | .unwrap(); 128 | 129 | if !output.status.success() { 130 | report_error(&format!( 131 | "Test failed:\n{}\n\x1b[1mFull code:\x1b[0m\n{}", 132 | String::from_utf8_lossy(&output.stderr), 133 | self.code, 134 | )); 135 | } 136 | 137 | std::fs::remove_file(file_path).unwrap(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{Parser, Subcommand}; 2 | use glob::glob; 3 | use indicatif::{ProgressBar, ProgressStyle}; 4 | use render::get_path_for_name; 5 | use serde::Serialize; 6 | use std::{path::Path, time::Duration}; 7 | 8 | mod comment; 9 | mod config; 10 | mod doctest; 11 | mod parser; 12 | mod render; 13 | mod report; 14 | mod templates; 15 | 16 | use report::{report_error, report_warning}; 17 | 18 | #[derive(Parser, Debug)] 19 | struct Cli { 20 | #[command(subcommand)] 21 | command: Commands, 22 | } 23 | 24 | #[derive(Serialize)] 25 | struct Pages { 26 | index: render::Page, 27 | extra: Vec, 28 | } 29 | 30 | #[derive(Serialize)] 31 | struct SearchIndex { 32 | id: i32, 33 | name: String, 34 | link: String, 35 | kind: String, 36 | } 37 | 38 | #[derive(Subcommand, Debug)] 39 | enum Commands { 40 | #[clap(name = "build", about = "Build documentation for the project")] 41 | Build { 42 | /// Dump JSON output 43 | #[clap(short, long)] 44 | dump_json: bool, 45 | 46 | /// Configuration file to use 47 | #[arg(short, long, default_value = "cppdoc.toml", value_name = "FILE")] 48 | config_file: Option, 49 | }, 50 | } 51 | 52 | fn main() { 53 | let args = Cli::parse(); 54 | 55 | match args.command { 56 | Commands::Build { 57 | dump_json, 58 | config_file, 59 | } => { 60 | let config_file = config_file.unwrap_or("cppdoc.toml".to_string()); 61 | 62 | let config = match config::Config::new(&config_file) { 63 | Ok(config) => config, 64 | Err(e) => { 65 | eprintln!("Error reading config file: {}", e); 66 | std::process::exit(1); 67 | } 68 | }; 69 | 70 | let clang = clang::Clang::new().unwrap(); 71 | let mut parser = parser::Parser::new(&clang); 72 | 73 | let mut output: parser::Output = Default::default(); 74 | 75 | let bar = ProgressBar::new_spinner(); 76 | 77 | for file in glob(&config.input.glob).expect("Failed to read glob pattern") { 78 | match file { 79 | Ok(file) => { 80 | bar.set_message(format!("Parsing {}", file.to_str().unwrap())); 81 | parser.parse(&config, file.to_str().unwrap(), &mut output); 82 | bar.tick(); 83 | }, 84 | Err(e) => { 85 | report_warning(&format!("Error reading input file: {e:}")); 86 | } 87 | }; 88 | 89 | } 90 | 91 | bar.finish_and_clear(); 92 | 93 | if dump_json { 94 | let json = serde_json::to_string_pretty(&output).unwrap(); 95 | println!("{}", json); 96 | return; 97 | } 98 | 99 | let root_namespace = if let Some(ref root_namespace) = config.output.root_namespace { 100 | // Find namespace 101 | output 102 | .root 103 | .namespaces 104 | .iter_mut() 105 | .find(|ns| ns.name == *root_namespace) 106 | .unwrap() 107 | } else { 108 | &mut output.root 109 | }; 110 | 111 | let mut doctests = Vec::new(); 112 | 113 | render::process_namespace(root_namespace, &output.index, &mut doctests, &config); 114 | 115 | let index = match config.pages.index { 116 | Some(ref x) => std::fs::read_to_string(x).unwrap(), 117 | None => match root_namespace.comment { 118 | Some(ref comment) => comment.description.clone(), 119 | None => String::new(), 120 | }, 121 | }; 122 | 123 | let index_html = 124 | render::process_markdown(&index, &output.index, &mut doctests, &config); 125 | 126 | let mut extra_pages = Vec::new(); 127 | 128 | for g in &config.pages.extra.clone().unwrap_or_default() { 129 | for file in glob(g).expect("Failed to read glob pattern") { 130 | match file { 131 | Ok(page_path) => { 132 | match std::fs::read_to_string(&page_path) { 133 | Ok(source) => { 134 | let mut page = 135 | render::process_markdown(&source, &output.index, &mut doctests, &config); 136 | if page.title.is_empty() { 137 | page.title = page_path.file_name().unwrap().to_string_lossy().into_owned(); 138 | } 139 | page.path = page_path; 140 | extra_pages.push(page); 141 | }, 142 | Err(e) => { 143 | report_warning(&format!("Error reading extra file “{page_path:?}”: {e}")); 144 | } 145 | }; 146 | }, 147 | Err(e) => { 148 | report_warning(&format!("Error reading extra file “{g}”: {e}")); 149 | } 150 | }; 151 | } 152 | } 153 | 154 | let pages = Pages { 155 | index: index_html, 156 | extra: extra_pages, 157 | }; 158 | 159 | if let Some(ref doctest_conf) = config.doctests { 160 | if doctest_conf.enable { 161 | let bar = ProgressBar::new(doctests.len() as u64); 162 | 163 | bar.set_style( 164 | ProgressStyle::with_template("Running doctest {pos}/{len}").unwrap(), 165 | ); 166 | 167 | if let None = doctest_conf.run { 168 | report_error("Doctests enabled but no run option specified"); 169 | std::process::exit(1); 170 | } 171 | 172 | if let None = doctest_conf.compiler_invocation { 173 | report_error("Doctests enabled but no compiler invocation specified"); 174 | std::process::exit(1); 175 | } 176 | 177 | for doc in doctests { 178 | let out = doc.compile(doctest_conf); 179 | 180 | if doctest_conf.run.unwrap() { 181 | doc.run(out); 182 | } 183 | 184 | bar.inc(1); 185 | } 186 | 187 | bar.finish_and_clear(); 188 | } 189 | } 190 | 191 | // Make directories 192 | std::fs::create_dir_all(&config.output.path) 193 | .map_err(|e| { 194 | report_error(&format!("Error creating output directory: {}", e)); 195 | std::process::exit(1); 196 | }) 197 | .unwrap(); 198 | 199 | for page in &pages.extra { 200 | let path = Path::new(&config.output.path).join(page.path.parent().unwrap_or_else(|| &Path::new(""))); 201 | std::fs::create_dir_all(path).map_err(|e| { 202 | report_error(&format!("Error creating output directory: {}", e)); 203 | std::process::exit(1); 204 | }) 205 | .unwrap(); 206 | } 207 | 208 | let tera = templates::init(&output.index, &config); 209 | let mut context = tera::Context::new(); 210 | 211 | context.insert("config", &config); 212 | context.insert("project", &config.project); 213 | context.insert("pages", &pages); 214 | 215 | for page in &pages.extra { 216 | context.insert("content", &page.content); 217 | context.insert("title", &page.title); 218 | 219 | std::fs::write( 220 | format!("{}/{}.html", config.output.path, page.path.display()), 221 | tera.render("docpage", &context).unwrap(), 222 | ) 223 | .map_err(|e| { 224 | report_error(&format!("Error writing extra page file: {}", e)); 225 | std::process::exit(1); 226 | }) 227 | .unwrap(); 228 | } 229 | 230 | std::fs::write( 231 | format!("{}/search.html", config.output.path), 232 | tera.render("search", &context).unwrap(), 233 | ) 234 | .map_err(|e| { 235 | report_error(&format!("Error writing search page file: {}", e)); 236 | std::process::exit(1); 237 | }) 238 | .unwrap(); 239 | 240 | let bar = ProgressBar::new_spinner(); 241 | bar.enable_steady_tick(Duration::from_millis(100)); 242 | bar.set_message("Rendering root namespace"); 243 | templates::output_namespace(root_namespace, &pages, &config, &output.index, &tera) 244 | .unwrap(); 245 | bar.finish_and_clear(); 246 | 247 | // Copy everything in the static directory to the output directory 248 | for entry in std::fs::read_dir(&config.output.static_dir).unwrap() { 249 | let entry = entry.unwrap(); 250 | let path = entry.path(); 251 | let filename = path.file_name().unwrap(); 252 | let dest = format!("{}/{}", config.output.path, filename.to_str().unwrap()); 253 | std::fs::copy(&path, &dest).unwrap(); 254 | } 255 | 256 | // Make a new, more searchable index 257 | let mut id: i32 = 0; 258 | let mut index = Vec::new(); 259 | 260 | for item in &output.index { 261 | index.push(SearchIndex { 262 | id, 263 | name: item.0.clone().replace("\"", """), 264 | link: match item.1.as_str() { 265 | "namespace" => { 266 | format!( 267 | "{}/index", 268 | get_path_for_name(item.0, &output.index).unwrap_or_default() 269 | ) 270 | } 271 | _ => get_path_for_name(item.0, &output.index).unwrap_or_default(), 272 | } 273 | .replace("\"", """) 274 | .to_string(), 275 | 276 | kind: item.1.clone(), 277 | }); 278 | 279 | id += 1; 280 | } 281 | 282 | // Add pages to the search index 283 | for page in &pages.extra { 284 | index.push(SearchIndex { 285 | id, 286 | name: page.title.clone(), 287 | link: page.path.to_string_lossy().into_owned(), 288 | kind: "page".to_string(), 289 | }); 290 | 291 | id += 1; 292 | } 293 | 294 | let index_json = serde_json::to_string_pretty(&index).unwrap(); 295 | 296 | std::fs::write( 297 | format!("{}/search_index.json", config.output.path), 298 | index_json, 299 | ) 300 | .unwrap(); 301 | 302 | println!("Documentation generated in {}", config.output.path); 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | use crate::comment; 2 | use crate::config; 3 | use serde::Serialize; 4 | use std::collections::HashMap; 5 | 6 | #[derive(Serialize, Debug, Clone)] 7 | pub struct Comment { 8 | pub description: String, 9 | pub brief: String, 10 | #[serde(rename = "impl")] 11 | pub impl_: Option>, 12 | } 13 | 14 | #[derive(Serialize, Debug, Clone)] 15 | pub enum NestedField { 16 | Record(Record), 17 | Enum(Enum), 18 | } 19 | 20 | #[derive(Serialize, Debug, Clone)] 21 | pub struct Field { 22 | pub name: String, 23 | #[serde(rename = "type")] 24 | pub type_: String, 25 | pub comment: Option, 26 | 27 | #[serde(rename = "struct")] 28 | pub struct_: Option, 29 | } 30 | 31 | #[derive(Serialize, Debug, Clone)] 32 | pub struct Record { 33 | pub name: String, 34 | pub fields: Vec, 35 | pub comment: Option, 36 | pub kind: String, 37 | pub namespace: Option, 38 | pub ctor: Vec, 39 | pub methods: Vec, 40 | pub template: Option