π Features
New features and additions
- β¨ Reflection-driven Handlebars DOM. d3fc5d5
- π« Reflection-driven generator schema. 46d5ec4
- π Support macros.1 (Closes #1127.) bf75eb5
- β¨ Uniform attribute extraction. (fix #1233) 8fe79f8 (thanks @correaa)
- π« JSON generator. (fix #841) 4eff461
- π Declare output generators from extension scripts.2 (object:
ctx.corpusandctx.configfor a transform, and additionally) 2ea48a6 - β¨ Support script-driven generators.3 ff8bb85
- π« Move template specializations and deduction guides off parent scope page.4 (issue: issue #1154.) 0d693e2
- π Render long noexcept specifications as noexcept(see-below).5 (issue: issue #1103.) a46693c
- β¨ Inline image and
rendering. d6070bb - π« Macro extraction options. 3fd5e35
- π Per-generator options. 3ab3a90
- β¨ LaTeX math command. (fix #1242) c1990cb (thanks @correaa)
- π« Multi-generator workflow.6 25f4f75
- π Extract symbols inside extern "C" and export blocks. dd56a2f
- β¨ Footnote references and definitions. ae8abf9
- π« Configurable noexcept see-below threshold. 27f3488
- π Expose per-extension parameters as ctx.params.7 197e765
- β¨ Ctx.stringify for script generators.8 1f696a8
- π« Render math via stem/MathJax. ce746e2
- π cmake: Find_package(mrdocs).9 b68b23c
- docs:
- β¨ Use brand theme colors. a51d162
- π« Light-mode support for the brand theme. faea11b
- π overloads: Merge overload-set attributes. 7d47dae
- extensions:
- β¨ Declare corpus transforms with register_transform.10 5db7b34
- π« Report warnings and errors from extensions. eb251e0
- tools:
- π Fix-docs documentation tool. 2171714
- β¨ Fix-docs convergence and strict-check parity.11 803b88e
- π« compilation-db: Cmake-build-dir option. (fix #762) 7f2a311 (thanks @anarthal)
- config:
- π Max-errors. f978289
- β¨ Warn-if-undocumented-namespace. 44ef126
- π« Warn-no-brief. d5177de
- π Non-standard-attributes. 202a43a
- β¨ ast: User-defined literal operators. c964b65
- π« javadoc: Language-tagged code blocks. 17aa971
- π support: MRDOCS_TRY_BIND for structured bindings. 1232a91
π Fixes
Bug fixes and error corrections
- ast:
- Implicit specializations reached as dependencies stay dependencies.12 (exception: the parent walk from a written declaration inside the) cd02bbf
- SFINAE parameter erased on every redeclaration. dbc643b
- Infinite recursion in SFINAE base-class walk. (fix #1270) 66eb1d8 (thanks @sdebionne)
- Collect all undocumented API symbols. 5bf467c
- Find doc comment of macro-prefixed members. 738a61e
- GenerateUSR skips inline namespaces. 5618fc1
- Force find doc comments false negatives. 8123b69
- Comment on a nested-namespace-definition documents the innermost namespace.13 db9fa4d
- Name typedef'd anonymous records. ee6b32d
- Instantiations written in a context are not traversed.14 2aad8da
- Members of private records are private. a6866d6
- Render true booleans as empty elements in XML.15 dd454b7
- Using-declarations off a dependent base are extracted.16 (Fixes #1258.) a858cba (thanks @correaa)
- Specializations and deduction guides are listed in order.17 (Fixes #1260.) ac3c5a8 (thanks @correaa)
- Conversion functions are named as written.18 (Fixes #1259.) 5cf8f57 (thanks @correaa)
- Macro member order.19 14a36c8
- Members re-exported via using reach further derived classes.20 6a7711f
- Re-enable ScriptGenerator unit tests. 54c91b1
- Symlink-tolerant path inclusion filter. (fix #1227) 3d254b6
- Nested types missing from tagfile. (fix #1232) b014649 (thanks @ashtum)
- Render inline markup correctly in Adoc and HTML.21 (issue: issue #1185.) 93225a4
- Separate Types and Type Aliases tables. (fix #1226) 9521a70
- Omit the synthesized initializer for default-constructed variables.22 (Closes #1238.) 04a1386 (thanks @gennaroprota)
- Disambiguate anchors that differ only in case.23 4415a2f
- Destroy C++ locals before raising a Lua error.24 ce432e6
- A JavaScript function value weakly references its interpreter.25 570fd0c
- Empty-corpus check ignores global namespace.26 116e980
- Clang resource directory missing from release packages. 1fc8a77
- Error-on-empty-corpus option. (fix #1222) 0d7f8b3
- Introduced symbols are listed by name.27 bd1c688
- Attribute-based detection for no_unique_address macros. e31308f
- Marshal Undefined and SafeString DOM values in Lua.28 9a42f36
- finalizers:
- Irregular inherited members copy location from base-specifier. 136e3bb
- Cycle guard in BaseMembersFinalizer. 63e25d0
- Drop inline namespaces from the corpus. 591b326
- docs:
- Documentation merge by missing fields. aa27b27
- Repair the demo gallery table.29 (docs: golden-test layout and snippet conventions, suite: XML is the default regression format, generator/hbs holds the) af2d368
- doc:
- generators:
- "Global index" heading for namespace-free libraries. 1db1fad
- Resolve using-directive targets to symbols. c735e01
- compilation:
- Drop GCC's builtin include dir from probed includes. 3d968eb
- System libc works with the bundled stdlib. f95f727
- support:
- Backtrack through enclosing stars in path globs. 1399ea4
- Normalize native path separators before glob matching. d93706d
- javadoc: tags without href warn instead of erroring. d6de22e
β»οΈ Refactor
Code refactoring and restructuring
- Xml generator is corpus reflection.32 e37b111
- Unify partials via data-level abstraction.33 e75cdff
- Encapsulated target layout. b79e66d
- Macros use regular symbol pipeline. 404dea0
- Specifiers hpp/cpp correspondence. 5de5385
- IsImplicitDefaultInit in ClangHelpers. c795d5d
- generators: Single build() entry point. 9e66c2f
- support: Path helpers. 8e3391a
- extensions: Register scripts through a
mrdocs object, not free functions.34 de70580
π Documentation
Documentation updates and improvements
- examples:
- Reuse common symbol template.35 b28ba4b
- Round-trip code snippets extension. (fix #620) 13c18f8
- Documented third-party demos. c43bf98
- No-op generator checks. 81b28e8
- Ghostwriter extension. 7610273
- Reflection generator. d5289d0
- Use let/const in the transform snippet scripts. de34d0c
- Table-of-contents script generator. (fix #174, #1078) eb701c6
- Project-conventions extension. 58f6259
- See-below placeholder override example. 310d357
- Bitcoin, folly, and openssl demos. 38414a4
- Exclude OpenSSL's generated symbols from mrdocs.yml.36 36ce5e3
- Shared highlight.js config for landing page. 4108a3f
- Script-driven JSON generator example. 792d25e
- Split the extensions page into transforms and generators. 03dccd4
- Landing snippets as headers. ff6f97f
- Merge generators into the extensions page.37 d109ef9
- Add a runnable script-driven generator example.38 2f27b2e
- Document script-driven generators. ab0062a
- Restore scroll-spy in the on-this-page TOC. 2252424
- Golden-test layout conventions. 0e85c60
- Readable options-reference colors in light mode. 8f9f43a
- Sqrt snippet is declaration only. 7cff518
- Antora-cpp-reference-extension 0.1.2. 63c52f9
- Local doc builds only include HEAD. ef17c3b
- Table of contents heading in the script generators page. 4878078
strikethrough syntax in commands registry. 32540a3
- Fix column count in the output-config table. a202442
- ui:
- Merge duplicate burgers. f657211
- Fix mermaid light mode font color. 286d9c3
- Highlight python code blocks. ef1360c
- Bold body text renders at normal weight. e19223f
- antora: Fall back to latest release when the version has none. cc4a519
- website:
- Distinct @note in terminate snippet. 5dc5a2c
- Fix landing page built-in formats. 46c200c
π¦οΈ Build
Build system and configuration changes
- bootstrap: Justfile run configuration generator. 40d2ef7
- Update justfile bootstrap notes. 491c000
- MRDOCS_MRDOCS_BUILD default is MRDOCS_BUILD. a5bb65d
π§ͺ Tests
Test cases and testing-related changes
- golden-tests:
- One generator per test and pruned expected outputs.39 57174d9
- Silence unnecessary warnings. 6371a19
- Reproducible runs from a suite-root marker. 6a010a1
- Using-declarations with nothing to point at.40 a7da531
- Add unit tests for script-driven generators.41 3243b87
- Cover register_generator declaration and lookup. f483a3d
- config: Out-of-tree base-url source link guard.42 (fix #1084) 2921b28
π¦ Continuous Integration
Changes related to continuous integration
- Master releases.43 47bdd69
- Merge-queue support and a leaner pipeline.44 f942a24
- Single-pass demo generation. e98b594
- Build the instrumented libc++ beside the plain one.45 ae86165
- Leaner merge-queue runs.46 0eb164f
- Limit full demos to pushes. 80f517e
- Upload demos before the documentation build. aebb9e5
- Drop third-party profraw from the coverage merge.47 117d320 780db10
- Dedicated build/mrdocs tree. 3791973 3ac24c0
- Build on push to any branch.48 64cfdbd
ποΈ Chores
Routine tasks, maintenance, and housekeeping
- Bump LLVM to 77e43ec1 (May 21, 2026).49 (PR: were initially doing in PR #1192.) eb3108a
CI CI
- Remove SSH_AUTH_SOCK conflict. 14bd9e3
-
This adds support for preprocessing macros: #define directives arecaptured via a clang::PPCallbacks subclass and exposed asMacroSymbol instances at the corpus root (macros aren't in any C++scope, so they sit alongside the global namespace rather than under it).Include guard macros are recognized and skipped.Filters apply to macros, too:- extract-all: when off, undocumented macros are dropped.- exclude-symbols, include-symbols, implementation-defined, see-below: matched against the macro name.- File-pattern filters: matched against the directive's source location.New output pages: multipage mode now produces macros.{ext} at theoutput root, listing every macro with a link to its per-symbol page. Theglobal-namespace page gains a "See also: Macros" navigation hint(multipage-only) so the new page is discoverable.Macro @param blocks are validated. β©
-
An extension script now defines an output generator withregister_generator(id, fn), alongside any register_transform itdeclares, rather than a generator directory shipping amrdocs-generator.yml that names a script. Both hooks receive one ctx``ctx.output for a generator. This replaces the positionalgenerate(corpus, output, config, params) entry point and the separatemanifest-script discovery pass.A registered generator is a dom::Function the corpus owns, because thegenerator registry is a process-global that is never cleared. The buildpopulates the corpus with the registered generators while extensionsrun; GenerateAction then resolves the requested generator from thecorpus before falling back to the registry. A single language-agnosticrunner invokes the function, so the two per-language generator runnerscollapse into one path.The manifest now carries only the data-driven generator fields, itsescape rules and the parent it extends; the script and params keysare gone. The search-index example moves under addons/extensions anddeclares its generator with register_generator. β©
-
This adds a generator flavor backed by a user script. A directory under/generator// whose mrdocs-generator.yml names a scriptinstalls a generator that hands the whole emit to a Lua or JavaScriptgenerate(corpus, output) function: the script walks the corpus andwrites files through the output object, so it can produce output shapesa per-page generator cannot, such as a single artifact aggregated acrossevery symbol.The manifest parser moves into a shared GeneratorManifest, so thedata-driven and script-driven discovery passes read the same file. Amanifest that names a script is skipped by the data-driven pass andinstalled by the script pass.The output object exposes a single write method, resolved under theoutput directory and forbidden from escaping it. Both languages receiveit as the second argument to generate; on the Lua side it is also boundas a global and passed from there, because the Lua bridge cannot carry acallable as a plain value. β©
-
Class template specializations, function template specializations, anddeduction guides used to share the enclosing scope's listing with theirprimary template. Users have repeatedly reported this as confusing: Aand A<int> appearing side by side in the namespace index reads as ifthey were independent siblings, and a primary's variants were nowhere onits own page.Specializations now appear in a dedicated "Specializations" section onthe primary's documentation page, and deduction guides in a "DeductionGuides" section on the deduced class's page. The parent scope's listingcarries only the primary itself. An orphan specialization (one whoseprimary has been excluded from extraction) stays in the parent's listingso the index can still reach it.The relationship is stored in the corpus: each primary record orfunction template carries the IDs of its specializations (and, for classtemplates, of its deduction guides), and each specialization carries anIsListedOnPrimary flag. The lists are populated by a finalizer passand exposed via reflection, so the XML output gains matching<specializations>, <deduction-guides>, and <is-listed-on-primary>elements and the DOM/Handlebars layer renders the new sections throughplain field access. β©
-
MrDocs used to render the full noexcept operand inline, so adeclaration like void swap(reference, reference) noexcept( std::is_nothrow_move_constructible<value_t>::value && std::is_nothrow_move_assignable<value_t>::value && std::is_nothrow_move_constructible<json_value>::value && std::is_nothrow_move_assignable<json_value>::value);buried the noexcept condition in a mostly-unreadable slop.This replaces operands longer than 40 characters with an italic"see-below" placeholder in the declaration, and moves the actualcondition to a dedicated "noexcept Specification" section of theexposition: void swap(reference, reference) noexcept(see-below); === noexcept Specification noexcept when ...long condition....The section is intentionally separate from the existing "Exceptions"section, which continues to cover @throws documentation. β©
-
The generator option now accepts a single id, a YAML sequence, or acomma-separated string, and the tool runs each generator in turn, so thecorpus is extracted once and rendered by every requested generator. A new built-in noop generator runs extraction and reports diagnostics without writing any output, which is useful for checking that extraction succeeds and surfacing warnings. β©
-
A script extension can now receive its own parameters as ctx.params,keyed by the id it registered under, or an empty object when none isset.For generators, this is the generator-options.<id> map (which alreadyexisted for per-generator settings) from mrdocs.yml. For transforms, itis a new transform-options.<id> map; to key it, register_transformnow takes a mandatory id - register_transform(id, fn) - matchingregister_generator(id, fn). β©
-
Give script-driven generators ctx.stringify(value), which serializes any value to JSON through the DOM encoder. JavaScript already has JSON.stringify; this gives Lua the same and behaves the same in both.Rewrite the search-index example to use it instead of hand-assembling JSON strings, and to use each symbol's anchor as the URL rather than id + ".html". β©
-
Find_package(mrdocs) was incorrect and untested. The exported configuration wasan old placeholder we never updated, so a consumer find_package(mrdocs) failed. This commit implements this feature so projects can consume mrdocs as an external library to build applications, extensions, and plugins.To make the package useful, we had to bundle the private dependencies (LLVM, Clang, JerryScript, Lua) into the mrdocs library. This is so a consumer can link mrdocs without installing the exact toolchain it was built with. Otherwise, extension users would be required to build and install mrdocs and all its dependencies from source.The change required a reorganization in the src/CMakeLists.txt scripts, as many options were hard-coded and non-idiomatic in ways that don't generalize for an installed package. We remove the old data/cmake/MrDocs.cmake / add_mrdocs() helper, as it was contradictory and hasn't been necessary for the project or maintained for years. It provided no benefit over a regular CMake custom target and had to be kept in sync with the CLI. Find_package now sets MRDOCS_EXECUTABLE, making it trivial to create custom targets. We also had to add an option to customize the clang-resource-dir so the installation can remain consistent with the canonical installation directory layout.We added tests/cmake, a standalone find_package(mrdocs) project that linksmrdocs::mrdocs-core into a small program and runs the installed binary over itsown source. It is exercised in the regular CI build and the release build. β©
-
This replaces the reserved-name transform_corpus(corpus) entry pointwith an explicit register_transform(fn) call. A script may registerany number of transforms; each runs once, in registration order, againsta navigable DOM view of the corpus it can read and mutate in place.The function is captured as a dom::Function on both languages. Luaanchors it in LUA_REGISTRYINDEX via the new lua::makeCallable, not astorage global, so no new ownerless global state is introduced. A scriptthat registers nothing warns and is otherwise a no-op, so an emptyscript is tolerated. β©
-
The tool builds its work-list from the same rules as the strict checkand points each task at the declaration that carries the comment. Itskips parameter tasks on a comment shared by overloads, skipsspecializations documented by their primary, parks tasks the agentdeclines, retries agent calls that fail on a rate limit, handlesnamespaces reopened across files, and stops only when a cycle changesnothing. β©
-
An implicit specialization is documented by its primary template: nobodywrote it. Reached as a base class it was already a dependency, butreached any other way while following a dependency, as the type of aparameter (AnalysisManager<Module>::Invalidator &) or through atypedef, it went through the symbol and file filters like a writtendeclaration and came out regular, with every instantiated member. OnLLVM that put 1444 such records in the corpus and, when Mr.Docs failedto carry the primary's comment to one of them, an undocumented symbolnobody can document; the fixtures that ask for S0<1> to decay to S0had recorded the opposite.The rule now holds in every non-regular traversal mode, with onespecialization, an explicit specialization of one of its members, stillgives it a place in the output to hold that member. β©
-
namespace a::b { opens one NamespaceDecl per component at the same place, and Clang hands the comment above it to every one of them, so a and b both got the brief. The comment describes what is being opened for the code that follows, the innermost namespace; the enclosing components are only the path to it. On LLVM every /// ... abovenamespace llvm::xray { also became a stray brief on llvm, and removing it left xray undocumented. The outer components now get no comment from the nested-namespace-definition and keep whatever their own declarations carry. β©
-
Instantiations such as extern template class A<int>; and template class A<int>; are uses of a template, not declarations or definitions of anything: they instantiate A for int, and what they name is documented where the template or its specialization is declared. The traversal was visiting them as members of their context, which made them regular, undocumented symbols located at the primary template's line. The strict check kept reporting them while the primary was fully documented (LLVM's extern template classELFFile<ELF32LE> and friends), and there was no line to put a comment on. They are now skipped where a context's members are enumerated, next to the implicit declarations that are skipped for the same reason. β©
-
The XML writer rendered every true boolean as the literal 1, forexample <is-inline>1</is-inline>. That 1 carried no informationbeyond the element's own presence (a false boolean was already omittedentirely).So, encode a true boolean by presence alone: emit an empty element(<is-inline/>) and drop the redundant body. Absence still means false. β©
-
A using-declaration of the kind TemplateParam::Name is unresolveduntil the template is instantiated, so Clang keeps it in anUnresolvedUsingValueDecl or UnresolvedUsingTypenameDecl rather thanin a UsingDecl with shadow declarations. Only the latter wastraversed, so re-exporting a member of a base that is itself a templateparameter left nothing in the documentation, and no diagnostic.The typename form is now recorded as such, dependent base or not,where it used to be recorded as a plain using. Note that setting thatclass for the first time exposed the signature partial rendering it asusing typenameBase::size_type, with no intervening space betweentypename and the name. β©
-
In both lists, all elements take the name of the primary, so comparingnames never decided anything, and the order fell through to the symbolIDs, which are hashes of the declaration.They now compare on what is there in them beyond that shared name: whata specialization was specialized with, and what a guide deduces, withthe types a guide takes deciding between guides that deduce the samething. β©
-
This fixes an issue for which operator CArray& came out as operator&, operator T::type as operator ::type, and operator fun_ptr asoperator void(*)().The empty names also collided, so conversions to unrelated types weregrouped as overloads of each other.Furthermore, a using-declaration that imports a conversion is named thesame way now. β©
-
SortMembers listed each tranche bucket by hand and never got updatedwhen the Macros bucket was added, so macros skipped the sort and renderedin extraction order.Iterate the tranche's members via describe::for_each_member instead, soevery bucket (Macros included) is sorted and new buckets stay in syncwithout touching this code. β©
-
A using-declaration is a member of the class that writes it, so a classderiving from that one inherits it. The buckets of a record tranche wereinherited from a list written out by hand, and the one holdingusing-declarations was missing from the list, so a member re-exportedfrom a base didn't reach classes further down the hierarchy.The buckets are discovered by reflection now, so the list cannot fallbehind again.A using-declaration re-exports a name rather than a signature, sowhatever a derived class declares under that name hides it. This is nowchecked in inheritBaseMembers. β©
-
Emphasis, subscript, and superscript in doc comments renderedincorrectly. Their common partials all delegated to the italic fallbackmarkup/i. In AsciiDoc that yields italics: right for emphasis, wrongfor subscript and superscript, which should be lowered and raised. InHTML markup/i has no counterpart, so emphasis collapsed to bare text;and the HTML inline dispatcher was a hardcoded list that omittedsubscript and superscript, dropping them altogether.Doc comments may now also use the HTML-tag form for theinline-formatting kinds (<strong>, <mark>, <del>, <s>, <sub>,<sup>), joining the previously-supported <em>. This is what mostusers reach for when they need tight notation (e.g. H<sub>2</sub>O);the Markdown-marker forms require whitespace flanks, which makes compactchemistry and math notation awkward.Footnote-reference, image, and math share the same italic-fallbackrendering but each needs its own design decision and is left forseparate fixes. β©
-
Default-constructed variables (T t;) were rendered with a spuriousinitializer (= t). That's because Clang represents them with animplicit construction expression located at the variable name; so theextracted initializer text was the variable name itself.Therefore, skip the initializer when it is an implicit defaultconstruction. β©
-
Two symbols in the same scope whose names differ only in case were given anchors that differ only in case too. On a case-insensitive filesystem those would become the same page. β©
-
luaL_error and lua_error report a failure by longjmp-ing to theenclosing lua_pcall. The jump runs no C++ destructors on the framesit unwinds, so any local with a non-trivial destructor still alive atthe point of the raise is leaked, and the unwind itself is undefined.Two of the Lua binding functions raised while such a local was live.The one invoked when a script assigns to a dom::Object field heldthe value being assigned and raised from inside a catch. The oneinvoked when a script calls a dom::Function held the argumentdom::Array, the call result, and the function being invoked.Stage the outcome on the Lua stack first - push the result value, orbuild a location-prefixed message with luaL_where and lua_concat -then close the scope so every C++ local is destroyed, and only thenraise. Lua copies a pushed string, so the message outlives thedestructors. β©
-
js::Context::~Context tore the JerryScript interpreter down on thefirst Context destruction, breaking the reference cycle between theImpl and the native holders that each keep a shared_ptr to it. Adom::Function obtained from a JavaScript value holds only thatshared_ptr, so once the originating Context was gone the functionreferred to a freed interpreter and calling it crashed.So, count only the live js::Context instances that share aninterpreter and tear it down when the last one goes away. A functionvalue converted to a dom::Function holds a weak reference and locksit on each call: once the interpreter is gone the call returns anerror instead of touching freed memory. Code that needs such afunction to outlive the Context that produced it keeps a Contextalive separately.Single-context use is unchanged: the count drops to zero on thatContext's destruction and cleanup runs as before. Handlebars helperswritten in JavaScript are unaffected; they hold the value directlyrather than through the function-value conversion. β©
-
The error-on-empty-corpus option compared the corpus against empty(), but the global namespace is always extracted and protected from pruning, so the corpus is never truly empty after a successful build, and the option never triggered. β©
-
The section handed the table the symbol IDs themselves, so ausing-declaration listed the hash of what it introduces instead of thename; and the descriptions went missing with it, because the test forwhether any of them is documented could not find a doc comment on an ID.They are resolved through the corpus now. β©
-
domValue_push handled Null, Boolean, Integer, String, Array,and Object, and aborted via MRDOCS_UNREACHABLE for any other kind.Reading a field whose value is Undefined or SafeString thereforecrashed a Lua script.This maps Undefined to nil, as Null already is, and a SafeStringthe way a String is, which matches what happens in JavaScript. β©
-
Add a top-level test-files/golden-tests/README.md describing the goldenminimal Handlebars rendering tests, and snippets are documentationexamples that render only the format the docs embed. Move the snippetsconvention here from snippets/README.md so the whole picture lives inone place. β©
-
A macro that expands to several functions on one line (LLVM's WRAP_BOTH:a static overload taking a predicate and a member overload takingnothing) gives them all the comment written above it; Clang attaches itto every declaration the expansion produces there, and Mr.Docs alreadystored it on each. \param P was then "missing" on one overload and"nonexistent" on the other, so no comment satisfied both. A documentedparameter that any function declared at the same file, line, and columnhas is now valid. The grouping is only built the first time a documentedname matches none of a function's own parameters, which is rare; thecolumn keeps functions written by hand on one line apart. β©
-
The auto-brief pass took a paragraph as the brief only when it contained plain text, so /// \c char8_t. gave a documented enum value with no brief. Any styled span, code, link, reference, or formula is visible content; only breaks and a @copydetails placeholder, which is resolved later into someone else's description, are not. β©
-
Make the XML representation use the standard XSD datatypes (xsd:boolean, xsd:integer, xsd:string) instead of ad hoc conventions. We use camelCase element names matching the DOM/JSON field names, and drive the whole generator from the metadata's compile-time reflection. β©
-
Make tables render from data. markup/table takes headers, items,and columns. Cells use the markup/cell partial. With this, we move the symbol page out of the per-format adoc and html templatesand into a single common/partials/symbol.hbs.This makes generators impossible to drift at the symbol level and data-driven generators much easier to write because they don't have to redefine the symbol template. β©
-
register_transform and register_generator were bare globals in theextension environment. This moves them onto a mrdocs global object,the way console is already provided, so a script writesmrdocs.register_transform(fn) / mrdocs.register_generator(id, fn).Among Lua-embedding applications that expose a "register an extension"call, a host namespace object is the prevailing convention - darktableuses dt.register_*, Aegisub aegisub.register_*, Redisredis.register_function - while bare globals are the exception.Note that the per-invocation ctx (ctx.corpus, ctx.output,ctx.config) is unchanged: only load-time declarations go throughmrdocs. β©
-
The symbol page now lives in a single common template, so thedata-driven examples no longer need their own symbol.<id>.hbs.Each example is just a handful of format-specific markup primitives(table, section, admonition, list items, paragraph, heading, brief)plus the layout wrappers. Everything else comes from common and html. β©
-
DEFINE_STACK_OF and DEFINE_LHASH_OF_EX create opaque structs, callback typedefs, and about 25 functions per type, for 108 types in the public headers. OpenSSL documents them once, generically, so the demo excludes the instances, along with the POSIX hostent struct that leaks in through the deprecated BIO_gethostbyname. β©
-
The corpus-extensions page and the script-driven-generators pagedocumented two halves of one feature: scripts under addons/extensionsthat declare transforms and generators through the register_* hooks.This folds the generator material into the extensions page, which nowcovers both hooks and the shared ctx object, and removes the separatepage. β©
-
This adds a self-contained search-index generator that the docs pageincludes and CI runs.The extensions/script-driven-generators.adoc example section nowincludes the manifest and the generate.lua from this fixture, so thedocumented example is exactly the one the test runs. β©
-
Each golden test now runs once, with the generator(s) it declares in its own config, instead of being run three times (xml, adoc, html). β©
-
Three using-declaration cases end up with no target. One is a base thatis a template parameter, covered by the fix in the previous commit. Theother two had no coverage at all:- A member of every base in a pack, where the qualifier depends on the pack, so nothing is named until instantiation.- A member of a base that is filtered out, where the target is dropped for being excluded or an implementation detail, while the qualifier survives in the name introduced by the declaration. β©
-
This covers discovery (a script manifest installs a ScriptGenerator),the output writer (writes under the root, rejects absolute and escapingpaths), and both runners against a synthetic corpus, asserting the filethey emit. A regression test reads a symbol with no name field,exercising the Undefined-to-nil marshaling. β©
-
Symbols inherited from a base declared outside source-root must not get a source-code link (the file is not in the tree), while in-tree symbols do. The test pins both halves of that guard. β©
-
Every push to master now gets its own GitHub Release. The publish job tags the commit with its date (2026.9.2, or 2026.9.2+1 for a second one on the same day) and starts the tag build. β©
-
With golden fixtures no longer drifting across three formats on everychange, the pipeline can run the full test set on every build and arebasing merge queue becomes practical: the queue can rebase a PR ontothe current tip and re-test it without the expected outputs churning.All actions are also bumped to their latest releases (cpp-actions tov1.9.5 and the GitHub-maintained actions to their node24 versions) sothe runner no longer warns about the deprecated node20 runtime. β©
-
The MSan and ASan jobs build MrDocs against a sanitizer-instrumentedlibc++. MSan requires that, since it reports false positives on anyuninstrumented code; ASan doesn't require it, but is more effective withit, through libc++'s container-overflow annotations.The pinned libc++ contains a self-guard (added upstream inllvm/llvm-project#168955) that errors out when an ASan-instrumentedlibc++ is parsed without ASan, and MrDocs parses libc++ with normalflags for the libcxx.cpp golden. So an instrumented libc++ can no longerdouble as the one MrDocs reads.Thus, install both an instrumented and an uninstrumented libc++.Specifically, install the instrumented libc++ into a prefix separatefrom the main LLVM build's plain libc++; needs_libcxx_runtimes stillselects it for Clang + ASan/MSan. MrDocs links the instrumented librarythrough libcxx_runtime_flags but parses the plain headers the mainbuild leaves at the LLVM install prefix.Also, move Clang ASan and MSan to the latest Clang, since building thepinned libc++ from source needs a recent one. β©
-
Only runs on develop delete and save the LLVM cache. Develop is the default branch and the only scope every PR, queue, master, and tag run can read from; a push to master used to wipe the shared entry by key and save a copy nobody else could see, leaving every macOS job rebuilding LLVM for an hour.Demos build every format only on push events, which are the runs that publish them. Merge-queue runs, manual dispatches, and PRs build XML-only to check extraction and skip the LLVM and BDE demos. β©
-
The coverage step globs build/ for *.profraw, which after the bump alsoholds the extracted LLVM source tree. That tree ships llvm-profdata testfixtures in an older raw-profile version that llvm-profdata rejects,failing the merge. Delete build/third-party profraw first; MrDocs' ownprofraw live elsewhere under build/. β©
-
The push trigger filtered branches with '*', which does not match a'/' in a branch name, so slashed branches like feat/x never built onpush. Use '**' so any branch builds on push. β©
-
The new pin includes llvm/llvm-project#198452, which attachesdocumentation comments to macro definitions. That is the prerequisitefor reading them from Clang directly instead of scanning the source, asThe pin was about six months behind, so this also adapts MrDocs to theClang API changes across that range:- USRGeneration.h moved from clang/Index/ to clang/UnifiedSymbolResolution/; the clang::index namespace and signatures are unchanged.- clang::DiagnosticConsumer::finish() was removed, so the collecting diagnostic consumer relies on the forwarded EndSourceFile() instead.- The driver option table moved to clang/Options/Options.h, with its enumerators now in clang::options and getDriverOptTable() in clang.- cl::getRegisteredOptions() now returns a DenseMap, so its entries expose .second instead of getValue().- SubstituteConstraintExpressionWithoutSatisfaction was re-synced with Clang's current implementation.Parsing the newer libc++ also needs a new vcruntime_new.h stub (itsalign_val_t.h now includes it under the vcruntime ABI) and C++ guards sostdbool.h, stdalign.h, and threads.h stop redefining some C++ keywordsas macros.The regenerated goldens change only because Clang's output drifted overthe six months: constrained templates and destructors get differentsymbol IDs from USR generation, though their structure is identical(requires-clause, dtor-overloads), and a few declaration locationschanged. β©