Filters

Filters are the gate at the front of the pipeline: they decide which symbols enter the documentation corpus at all. MrDocs filters by qualified name, by where the source sits on disk, and by category (undocumented declarations, private members, friends, and so on), and it can hide the implementation details of a type without dropping it from the corpus. Once a symbol has cleared the filters, Extraction decides how MrDocs presents it. The Filters reference lists every option.

Name filters

The most common filter in C++ libraries is by qualified name. include-symbols keeps only the symbols whose names match one of the listed globs. The usual entry point is the library’s top-level namespace. exclude-symbols then drops a glob inside that set. Two patterns are common: the unsafe_* family of functions (faster variants that skip validation, on the assumption the caller has already validated), and a helper namespace like jzon::extra for tracing or debug hooks the public docs do not need.

include/jzon/parser.hpp
namespace jzon {

/// A parsed JSON document.
class value;

/** Validate that the document is well-formed JSON.

    Parses `source` without constructing a value tree, reporting only
    whether the input conforms to RFC 8259.

    @param source A null-terminated UTF-8 JSON document.
    @return `true` if the document is syntactically valid JSON.
*/
bool validate(char const* source);

/** Parse a JSON document.

    Validates `source` and returns the resulting value tree.

    @param source A null-terminated UTF-8 JSON document.
*/
value parse(char const* source);

/** Parse a JSON document without validating.

    Assumes the caller has already verified `source` with @ref validate.
    The behavior is undefined if `source` is not well-formed JSON.
*/
value unsafe_parse(char const* source);

/** Count the number of top-level elements in `source`.

    Assumes the caller has already verified `source` with @ref validate.
*/
unsigned long unsafe_element_count(char const* source);

}
include/jzon/extra/utilities.hpp
namespace jzon::extra {

/// Turn on parser tracing for the current thread.
void enable_trace();

/// Turn off parser tracing for the current thread.
void disable_trace();

}
mrdocs.yml
include-symbols:
  - 'jzon::**'
exclude-symbols:
  - 'jzon::unsafe_*'
  - 'jzon::extra::**'
Preview
jzon::value

A parsed JSON document.

Synopsis

Declared in <jzon/parser.hpp>

class value;
Non-Member Functions

Name

Description

parse

Parse a JSON document.

jzon::parse

Parse a JSON document.

Synopsis

Declared in <jzon/parser.hpp>

value
parse(char const* source);
Description

Validates source and returns the resulting value tree.

Return Value

A parsed JSON document.

Parameters

Name

Description

source

A null‐terminated UTF‐8 JSON document.

jzon::validate

Validate that the document is well‐formed JSON.

Synopsis

Declared in <jzon/parser.hpp>

bool
validate(char const* source);
Description

Parses source without constructing a value tree, reporting only whether the input conforms to RFC 8259.

Return Value

true if the document is syntactically valid JSON.

Parameters

Name

Description

source

A null‐terminated UTF‐8 JSON document.

Three patterns drive that output:

  • include-symbols: ['jzon::**'] keeps the whole jzon namespace.

  • exclude-symbols: ['jzon::unsafe_*'] then removes unsafe_parse and unsafe_element_count, so only the safe overloads land in the public docs.

  • exclude-symbols: ['jzon::extra::**'] removes the jzon::extra helper functions.

The pattern delimiter is :: instead of /. A single * matches anything that does not cross a ::, so jzon::* matches jzon::parse but not jzon::extra::enable_trace. A double ** matches everything including ::, so jzon::** matches both.

The Doxygen option analogous to exclude-symbols is EXCLUDE_SYMBOLS. Doxygen has no inclusion counterpart. It documents everything by default and narrows the set with the EXTRACT_* family plus EXCLUDE_SYMBOLS.

Implementation details

Sometimes a type that lives in the library’s implementation appears in a public signature: a return type, a parameter, an inherited base. Dropping it with exclude-symbols would break cross-references and leave the reference as a bare name. The two options below keep the symbol in the corpus and hide its details from the reader.

implementation-defined drops the page for the matched symbols and renders any reference to them as /* implementation-defined */. see-below is gentler: the symbol keeps its page, but the synopsis collapses to /* see-below */ and the members are not enumerated. Use see-below when the type matters to the reader but its implementation does not. Use implementation-defined when the type’s name should not be advertised.

include/logr/log.hpp
namespace logr {

/// The library's private encoder representation.
class encoder_impl;

/** A complete log record.

    Carries the message text and the level at which the record was
    emitted. Construct one and hand it to @ref emit().
*/
class log_record
{
public:
    log_record(char const* message) noexcept;

    char const* message() const noexcept;
    char const* level_name() const noexcept;

private:
    char const* message_;
    int level_;
};

/** Attach a key/value pair to every log line in the current scope.

    The context stays attached until the returned token is destroyed.
    Hold it in `auto`; nested contexts stack and unwind in reverse order.

    @param key   The context name surfaced on each log line.
    @param value The context value surfaced on each log line.
    @return An opaque RAII token whose lifetime governs how long the
            pair stays attached.
*/
detail::scope_token scoped_context(char const* key, char const* value);

/** Replace the active encoder.

    Obtain an encoder via @ref make_json_encoder() or
    @ref make_text_encoder() and hand it here.

    @par Example
    @code
    logr::set_encoder(logr::make_json_encoder());
    @endcode
*/
void set_encoder(encoder_impl&& enc);

}
include/logr/detail/scope_token.hpp
namespace logr::detail {
struct scope_token { ~scope_token(); };
}
mrdocs.yml
implementation-defined:
  - 'logr::detail::**'
  - 'logr::*_impl'
see-below:
  - 'logr::log_record'
Preview
logr::log_record

A complete log record.

Synopsis

Declared in <logr/log.hpp>

class log_record { /* see-below */ };
Description

Carries the message text and the level at which the record was emitted. Construct one and hand it to emit().

logr::scoped_context

Attach a key/value pair to every log line in the current scope.

Synopsis

Declared in <logr/log.hpp>

/* implementation-defined */
scoped_context(
    char const* key,
    char const* value);
Description

The context stays attached until the returned token is destroyed. Hold it in auto; nested contexts stack and unwind in reverse order.

Return Value

An opaque RAII token whose lifetime governs how long the pair stays attached.

Parameters

Name

Description

key

The context name surfaced on each log line.

value

The context value surfaced on each log line.

logr::set_encoder

Replace the active encoder.

Synopsis

Declared in <logr/log.hpp>

void
set_encoder(/* implementation-defined */&& enc);
Description

Obtain an encoder via make_json_encoder() or make_text_encoder() and hand it here.

Example
logr::set_encoder(logr::make_json_encoder());
Parameters

Name

Description

enc

The library's private encoder representation.

implementation-defined matches two patterns. 'logr::detail::**' catches the conventional internal namespace, and 'logr::*_impl' catches the _impl-suffixed forward declarations the library uses as opaque customization-point handles. Where either type appears in the signature of scoped_context or set_encoder, the rendered synopsis substitutes /* implementation-defined */. see-below matches logr::log_record: the type keeps its page, but the synopsis on that page collapses to /* see-below */, so the reader sees what the type is rather than how it is laid out.

When the set of implementation symbols is small or awkward to describe with a glob, use the @implementationdefined and @seebelow doc-comment commands instead. Same effect, declared next to the symbol rather than in the config.
Doxygen has no direct analogue. Marking a symbol with the \internal command plus INTERNAL_DOCS=NO hides it from the output, but Doxygen does not render references to it as "implementation-defined" or collapse its synopsis to "see-below".

Path filters

Reach for path filters when the libraries you want to keep share a naming scheme that a symbol filter cannot separate, or when the source tree contains directories (vendored code, generated headers) that should not appear in the docs at all.

input is the list of directories MrDocs scans for sources. A miniature FFmpeg layout makes the case: every public function across libavcodec, libavformat, and friends sits at global scope under the same av_* prefix, so include-symbols: ['av_*'] would pull them all in. Only the directory tells them apart.

include/libavcodec/avcodec.h
/** Allocate a new packet on the heap. */
int av_packet_alloc(void);

/** Release a packet allocated with `av_packet_alloc`. */
void av_packet_free(void);
include/libavformat/avformat.h
// Filtered out: `input: include/libavcodec` scopes extraction to that
// directory, so the format-library functions never enter the corpus.
// The directory matters because both libraries put their declarations
// at global scope under the same `av_*` prefix, so a name-based filter
// could not distinguish them.
int av_open_input_file(void);
void av_close_input_file(void);
mrdocs.yml
input:
  - include/libavcodec
Preview
av_packet_alloc

Allocate a new packet on the heap.

Synopsis

Declared in <libavcodec/avcodec.h>

int
av_packet_alloc();
av_packet_free

Release a packet allocated with av_packet_alloc.

Synopsis

Declared in <libavcodec/avcodec.h>

void
av_packet_free();

Only include/libavcodec is in input, so the format-library functions never enter the corpus. The default is <source-root>/., which covers the whole project.

recursive decides whether MrDocs walks into subdirectories under each input root. Set it to false when only the top-level files of a directory are public.

The exclusion side of the same axis: exclude drops a specific subdirectory inside input. Use it for code that does not belong in the output, such as a vendored copy of a third-party library or a generated-code tree that lives next to the source. The example below documents the httpd library while skipping a vendored copy of zlib that the project bundles for convenience:

include/httpd/server.hpp
namespace httpd {

/** Start the HTTP server on `port`. */
void start(int port);

/** Stop the running server. */
void stop();

}
include/zlib/zlib.h
// Vendored copy of zlib's public API. Documented upstream at
// https://zlib.net/, not here. `exclude: include/zlib` keeps the
// vendored library out of the rendered docs so it does not appear
// alongside the httpd API.

/* Compress `src` into `dst` using DEFLATE. */
int compress2(unsigned char* dst, unsigned long* dstLen,
              unsigned char const* src, unsigned long srcLen,
              int level);

/* Decompress a DEFLATE-compressed buffer. */
int uncompress(unsigned char* dst, unsigned long* dstLen,
               unsigned char const* src, unsigned long srcLen);
mrdocs.yml
exclude:
  - include/zlib
Preview
httpd::start

Start the HTTP server on port.

Synopsis

Declared in <httpd/server.hpp>

void
start(int port);
httpd::stop

Stop the running server.

Synopsis

Declared in <httpd/server.hpp>

void
stop();

exclude-patterns is the glob form of exclude and matches across the tree, so one pattern can drop every directory matching the glob no matter where it sits under input. The classic case is build-generated headers that live next to each component’s hand-written ones under a _generated/ subdirectory:

include/storage/storage.hpp
namespace storage {

/** Persist a value under `key`. */
void put(char const* key, char const* value);

}
include/storage/_generated/messages.hpp
// Generated by the build (protoc, gRPC, OpenAPI, …); do not edit by
// hand. Every component in this project keeps its generated headers
// next to the hand-written ones under a `_generated/` subdirectory,
// so `exclude-patterns: '**/_generated/**'` drops them all at once.

namespace storage::gen {
struct PutRequest {};
struct PutResponse {};
}
include/payments/payments.hpp
namespace payments {

/** Authorize a payment of `amount` against `account`. */
bool authorize(char const* account, double amount);

}
include/payments/_generated/messages.hpp
namespace payments::gen {
struct AuthorizeRequest {};
struct AuthorizeResponse {};
}
mrdocs.yml
exclude-patterns:
  - '**/_generated/**'
Preview
payments::authorize

Authorize a payment of amount against account.

Synopsis

Declared in <payments/payments.hpp>

bool
authorize(
    char const* account,
    double amount);
storage::put

Persist a value under key.

Synopsis

Declared in <storage/storage.hpp>

void
put(
    char const* key,
    char const* value);

A single '**/_generated/**' pattern drops both storage/_generated/ and payments/_generated/. With the literal exclude:, you would need one entry per directory.

file-patterns narrows the file set MrDocs scans inside the input directories: only files whose names match one of the globs are read. The default already covers the common C++ header extensions, so you set it only to narrow further (for example, to skip .ipp).

exclude and exclude-patterns are for code that should not appear in the docs at all, such as vendored libraries or generated code. Do not reach for them when the directory holds your own library’s private internals. Dropped symbols leave the corpus entirely, so any reference to one from a kept declaration renders as the literal name (detail::cache_entry) instead of an implementation marker. For your own internals, use the implementation-defined and see-below options covered above. They keep the cross-references intact and render them as /* implementation-defined */ or collapse the synopsis to /* see-below */.
The analogous Doxygen options are INPUT, RECURSIVE, EXCLUDE, EXCLUDE_PATTERNS, and FILE_PATTERNS.

Category filters

The extract-* family flips MrDocs’s category-level defaults: each option toggles a class of declarations that the default would either include or omit. The two most common are below. The reference page covers the rest (static locals, anonymous and empty namespaces, friends, local classes, implicit template specializations); reach for one when you discover the default is hiding something you wanted documented.

Undocumented symbols

extract-all decides whether MrDocs documents declarations that have no doc comment. The default true pulls them in; set it to false to keep the public docs to the symbols the author has explicitly written prose for:

Example
/// A documented function.
void documented();

// An undocumented function. The default `extract-all: true`
// would pull it in even without a doc comment; setting
// `extract-all: false` hides it.
void undocumented();
mrdocs.yml
extract-all: false
Preview
documented

A documented function.

Synopsis

Declared in <extract‐all.cpp>

void
documented();

documented survives; undocumented is dropped because no doc comment is attached.

Private members

extract-private adds private members to a class’s page, with companion switches extract-private-virtual and extract-private-bases for private overrides and private bases:

Example
/// A class with both public and private members.
class widget
{
public:
    /// Display the widget.
    void show();

private:
    /// An internal counter.
    int count;
};
mrdocs.yml
extract-private: true
Preview
widget

A class with both public and private members.

Synopsis

Declared in <extract‐private.cpp>

class widget;
Member Functions

Name

Description

show

Display the widget.

Private Data Members

Name

Description

count

An internal counter.

widget::show

Display the widget.

Synopsis

Declared in <extract‐private.cpp>

void
show();
widget::count

An internal counter.

Synopsis

Declared in <extract‐private.cpp>

int count;

Glob syntax

Symbol and file patterns share the same wildcards (the file form uses / as the path delimiter; the symbol form uses ::):

  • * matches all characters except the delimiter.

  • ** matches all characters including the delimiter.

  • ? matches any single character.

  • [<chars>] matches one character in the bracket; ranges work as [a-z]; negate with [^<chars>] or [!<chars>].

  • {<glob>,…​} matches one of the globs in the list.

  • \ escapes the next character so it is treated as a literal.

Inclusion rules

Inclusion rules (include-symbols, implementation-defined, see-below) are intentionally looser than exclude-symbols: a symbol counts as included when any of the following hold.

  1. The symbol strictly matches one of the patterns. std::vector matches both std::vector and std::*.

  2. The symbol is a parent namespace of an included symbol. std::filesystem::* therefore also pulls in std and std::filesystem.

  3. The parent symbol is included. std::* matches std::vector::iterator because std::vector matches.

  4. A literal pattern that names a namespace pulls in everything under it. std behaves like std::**.

Exclusion rules require a strict match: a symbol is excluded only when it (or its scope) is the pattern’s exact target.