Skip to content

Commit 51e2b65

Browse files
committed
feat(metadata): support recursive inline elements in documentation
1 parent 8f98077 commit 51e2b65

File tree

510 files changed

+16751
-17117
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

510 files changed

+16751
-17117
lines changed

.github/workflows/ci.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,71 @@ jobs:
497497
# The schema in the docs folder is valid
498498
npx -y -p ajv-cli -- ajv compile -s docs/mrdocs.schema.json
499499
500+
- name: Verify snippet .cpp files match golden tests (bash)
501+
shell: bash
502+
run: |
503+
set -euo pipefail
504+
shopt -s nullglob
505+
506+
SRC="docs/website/snippets"
507+
DST="test-files/golden-tests/snippets"
508+
509+
[[ -d "$SRC" ]] || { echo "Source directory not found: $SRC"; exit 2; }
510+
[[ -d "$DST" ]] || { echo "Destination directory not found: $DST"; exit 2; }
511+
512+
missing=()
513+
mismatched=()
514+
515+
# Walk all .cpp files under SRC
516+
while IFS= read -r -d '' src; do
517+
rel="${src#$SRC/}"
518+
dst="$DST/$rel"
519+
520+
if [[ ! -f "$dst" ]]; then
521+
missing+=("$rel")
522+
continue
523+
fi
524+
525+
if [[ "${STRICT_EOL:-0}" == "1" ]]; then
526+
# strict byte-for-byte comparison
527+
if ! cmp -s -- "$src" "$dst"; then
528+
mismatched+=("$rel")
529+
fi
530+
else
531+
# ignore CRLF/LF differences using git diff (available on all runners)
532+
if ! git diff --no-index --ignore-cr-at-eol --quiet -- "$src" "$dst"; then
533+
mismatched+=("$rel")
534+
fi
535+
fi
536+
done < <(find "$SRC" -type f -name '*.cpp' -print0)
537+
538+
if (( ${#missing[@]} || ${#mismatched[@]} )); then
539+
if (( ${#missing[@]} )); then
540+
echo "Missing corresponding golden files:"
541+
printf ' %s\n' "${missing[@]}"
542+
fi
543+
if (( ${#mismatched[@]} )); then
544+
echo "Content mismatches:"
545+
printf ' %s\n' "${mismatched[@]}"
546+
fi
547+
exit 1
548+
fi
549+
550+
echo "All snippet .cpp files are present and match."
551+
env:
552+
# Set to "1" to enforce byte-for-byte equality (do not ignore CRLF/LF)
553+
STRICT_EOL: "0"
554+
555+
556+
- name: Check landing page snippets
557+
run: |
558+
# Find python
559+
python=$(command -v python3 || command -v python)
560+
# The schema in this branch is up to date
561+
"$python" ./util/generate-yaml-schema.py --check
562+
# The schema in the docs folder is valid
563+
npx -y -p ajv-cli -- ajv compile -s docs/mrdocs.schema.json
564+
500565
- name: Upload GitHub Release Artifacts
501566
if: ${{ matrix.is-main && matrix.compiler != 'clang' }}
502567
uses: actions/upload-artifact@v4

docs/modules/ROOT/pages/commands.adoc

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
= Commands
22

3-
The code should be documented with the https://docs.oracle.com/en/java/javase/13/docs/specs/javadoc/doc-comment-spec.html[Doc Comment,window=_blank] format, also informally known as "javadoc" format or Doxygen-style comments.
3+
The code should be documented with the https://docs.oracle.com/en/java/javase/13/docs/specs/javadoc/doc-comment-spec.html[Doc Comment,window=_blank] format, also informally known as Javadoc-style or Doxygen-style comments.
44
55
In its most basic form, these are usually comment blocks between `pass:[/**]` and `pass:[*/]` placed above a class, function, or field declaration:
66
@@ -43,6 +43,64 @@ Most doc comments will contain these two sections, which could also be explicitl
4343
Doc comments can also contain many special commands, such as `@param`, that are used to document the parameters of a function.
4444
Mr. Docs supports most commands commonly used in Javadoc and Doxygen comments.
4545
46+
== Documentation Comment Formats
47+
48+
The documentation format used by MrDocs has its roots in earlier tools and languages. It is based on writing structured comments directly in the source code, which are then parsed to generate API reference documentation.
49+
50+
* **Origins: Javadoc**: The format originated with Java and the `doc` tool.
51+
The https://docs.oracle.com/en/java/javase/17/docs/specs/doc/doc-comment-spec.html[official specification] consistently calls these comments *Documentation Comments*, often abbreviated as "doc comments". In practice, many developers also refer to them as *Javadoc-style comments* due to their close association with the `doc` tool.
52+
* **Doxygen**: When Doxygen was created to support C, C++, and other languages, it adopted a similar comment style. In its https://www.doxygen.nl/manual/docblocks.html[documentation section about this comment style], Doxygen calls these comments *comment blocks*, but also explains them as *Javadoc style comments* for users familiar with the Java ecosystem. This established the convention of using the same recognizable syntax (`/** ... */`) across different ecosystems.
53+
* **JSDoc**: For JavaScript, the https://jsdoc.app/[JSDoc] tool introduced the same concept. Developers usually refer to them as *JSDoc comments*, again following the tradition of naming the comments after the tool.
54+
55+
Other ecosystems have adopted similar approaches and comment styles, sometimes with different syntax:
56+
57+
- C#: XML documentation comments (`/// ...`)
58+
- Rust: doc comments (`/// ...` and `//! ...`)
59+
- Swift: markup-based documentation comments (`/// ...`)
60+
61+
[cols="1,1,2,2",options="header"]
62+
|===
63+
| Language | Tool | Official Term | Common Term
64+
65+
| Java
66+
| Javadoc
67+
| https://docs.oracle.com/en/java/javase/17/docs/specs/doc/doc-comment-spec.html[Documentation comments]
68+
| Javadoc-style comments
69+
70+
| C, C++, etc.
71+
| Doxygen
72+
| https://www.doxygen.nl/manual/docblocks.html[Comment blocks]
73+
| Doxygen-style comments
74+
75+
| JavaScript
76+
| JSDoc
77+
| https://jsdoc.app/[JSDoc comments]
78+
| -
79+
80+
| C#
81+
| XML Documentation Comments
82+
| https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/[XML documentation comments]
83+
| -
84+
85+
| Rust
86+
| Rustdoc
87+
| https://doc.rust-lang.org/rustdoc/the-doc-attribute.html[Doc comments]
88+
| -
89+
90+
| Swift
91+
| Swift Markup
92+
| https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/[Markup documentation comments]
93+
| -
94+
|===
95+
96+
Briefly summarizing the table above:
97+
98+
- The original term, from Java, is *doc comments*. Other tools follow a similar convention.
99+
- Many tools and communities prefer to call them after the tool name, e.g. *Javadoc-style comments*, *Doxygen-style comments*, or *JSDoc-style comments*.
100+
- MrDocs follows this tradition by supporting a familiar syntax that developers across ecosystems already recognize.
101+
102+
103+
46104
// == Style
47105
//
48106
// The following commands can be used to format the text in the doc comments:

docs/modules/ROOT/pages/contribute.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ As a last step, `DoGenerateAction` converts the public `Config` settings into a
4949
[#representing_symbols]
5050
== Representing Symbols
5151

52-
MrDocs has many categories of objects, where we utilize polymorphism with a fixed set of valid derived types, including Symbols (functions, classes, and enums), Javadoc blocks, template parameters, template arguments, and data types. For each such family, we follow a consistent file layout. Most of these families are defined in the `mrdocs/Metadata` directory.
52+
MrDocs has many categories of objects, where we utilize polymorphism with a fixed set of valid derived types, including Symbols (functions, classes, and enums), DocComment blocks, template parameters, template arguments, and data types. For each such family, we follow a consistent file layout. Most of these families are defined in the `mrdocs/Metadata` directory.
5353

5454
Each base class is defined in its own header and, when necessary, implementation file. Each derived class also has its own header and implementation file. Finally, there is a single aggregator header file that includes all the derived headers. This file centralizes logic that requires knowledge of the full set of variants, such as visitors, comparison operators, and other operations that depend on the discriminator.
5555

@@ -144,7 +144,7 @@ are merged into a map containing the merged results from all other TUs.
144144
The merging step is necessary as there may be multiple identical definitions of the same entity.
145145
For instance, this represents the case where a function is declared at different points in the code base and might have different attributes or comments.
146146
At this step, the doc comments are also finalized.
147-
Each `Symbol` object has a pointer to its `Javadoc` object (`mrdocs/Metadata/Javadoc.hpp`), which is a representation of the documentation comments.
147+
Each `Symbol` object has a pointer to its `DocComment` object (`mrdocs/Metadata/DocComment.hpp`), which is a representation of the documentation comments.
148148

149149
After AST traversal and `Symbol` merging, the result is stored as a map of `Symbol` objects indexed by their respective `SymbolID`.
150150
A second finalization step is then performed in `mrdocs::finalize`, where any references to `SymbolID` objects that don't exist are removed.

docs/modules/ROOT/pages/index.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
= Mr.Docs
22
Alan Freitas <alandefreitas@gmail.com>
3-
:description: Mr.Docs: A Clang/LLVM tool for building reference documentation from C++ code and javadoc comments.
3+
:description: Mr.Docs: A Clang/LLVM tool for building reference documentation from C++ code and documentation comments.
44
:sectanchors:
55
:url-repo: https://github.com/cppalliance/mrdocs
66
:page-tags: mrdocs

docs/website/snippets/is_prime.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
55
Linear in n.
66
7-
@return Whether or not n is prime.
7+
@return Whether `n` is prime.
88
@param n The number to test
9-
109
*/
1110
bool
1211
is_prime(unsigned long long n) noexcept;

include/mrdocs/ADT/ArrayView.hpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//
2+
// This is a derivative work. originally part of the LLVM Project.
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com)
8+
//
9+
// Official repository: https://github.com/cppalliance/mrdocs
10+
//
11+
12+
#ifndef MRDOCS_API_ADT_ARRAYVIEW_HPP
13+
#define MRDOCS_API_ADT_ARRAYVIEW_HPP
14+
15+
#include <mrdocs/Platform.hpp>
16+
#include <algorithm>
17+
#include <cassert>
18+
#include <compare>
19+
#include <cstddef>
20+
#include <iterator>
21+
#include <memory>
22+
#include <type_traits>
23+
24+
namespace mrdocs {
25+
26+
/** A non-owning, read-only view over a contiguous array of T.
27+
28+
Similar to std::string_view but for arbitrary element type T.
29+
*/
30+
template <class T>
31+
class ArrayView {
32+
static_assert(!std::is_void_v<T>, "ArrayView<void> is ill-formed");
33+
34+
public:
35+
// types
36+
using value_type = T;
37+
using size_type = std::size_t;
38+
using difference_type = std::ptrdiff_t;
39+
using pointer = const T*;
40+
using const_pointer = const T*;
41+
using reference = const T&;
42+
using const_reference = const T&;
43+
using iterator = const T*;
44+
using const_iterator = const T*;
45+
using reverse_iterator = std::reverse_iterator<const_iterator>;
46+
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
47+
48+
static constexpr size_type npos = static_cast<size_type>(-1);
49+
50+
// ctors
51+
constexpr ArrayView() noexcept = default;
52+
53+
constexpr ArrayView(const T* data, size_type count) noexcept
54+
: data_(data), size_(count) {}
55+
56+
template <size_type N>
57+
constexpr ArrayView(const T (&arr)[N]) noexcept
58+
: data_(arr), size_(N) {}
59+
60+
template <class It>
61+
requires (std::contiguous_iterator<It> &&
62+
std::same_as<std::remove_cv_t<std::remove_reference_t<std::iter_value_t<It>>>, T>)
63+
constexpr ArrayView(It first, size_type count) noexcept
64+
: data_(std::to_address(first)), size_(count) {}
65+
66+
// iterators
67+
constexpr const_iterator begin() const noexcept { return data_; }
68+
constexpr const_iterator end() const noexcept { return data_ + size_; }
69+
constexpr const_iterator cbegin() const noexcept { return begin(); }
70+
constexpr const_iterator cend() const noexcept { return end(); }
71+
constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
72+
constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
73+
74+
// capacity
75+
constexpr size_type size() const noexcept { return size_; }
76+
constexpr size_type length() const noexcept { return size_; }
77+
[[nodiscard]] constexpr bool empty() const noexcept { return size_ == 0; }
78+
79+
// element access
80+
constexpr const_reference operator[](size_type i) const noexcept {
81+
return data_[i];
82+
}
83+
constexpr const_reference at(size_type i) const {
84+
assert(i < size_);
85+
return data_[i];
86+
}
87+
constexpr const_reference front() const {
88+
assert(!empty());
89+
return data_[0];
90+
}
91+
constexpr const_reference back() const {
92+
assert(!empty());
93+
return data_[size_ - 1];
94+
}
95+
constexpr const_pointer data() const noexcept { return data_; }
96+
97+
// modifiers (adjust the view; do not touch underlying data)
98+
constexpr void remove_prefix(size_type n) noexcept {
99+
assert(n <= size_);
100+
data_ += n;
101+
size_ -= n;
102+
}
103+
constexpr void remove_suffix(size_type n) noexcept {
104+
assert(n <= size_);
105+
size_ -= n;
106+
}
107+
108+
// slicing
109+
constexpr ArrayView slice(size_type pos, size_type count = npos) const noexcept {
110+
assert(pos <= size_);
111+
const size_type rcount = (count == npos || pos + count > size_) ? (size_ - pos) : count;
112+
return ArrayView(data_ + pos, rcount);
113+
}
114+
constexpr ArrayView take_front(size_type n) const noexcept {
115+
return slice(0, n <= size_ ? n : size_);
116+
}
117+
constexpr ArrayView take_back(size_type n) const noexcept {
118+
n = (n <= size_) ? n : size_;
119+
return slice(size_ - n, n);
120+
}
121+
constexpr ArrayView drop_front(size_type n) const noexcept {
122+
return (n >= size_) ? ArrayView() : ArrayView(data_ + n, size_ - n);
123+
}
124+
constexpr ArrayView drop_back(size_type n) const noexcept {
125+
return (n >= size_) ? ArrayView() : ArrayView(data_, size_ - n);
126+
}
127+
128+
// comparisons
129+
friend constexpr bool operator==(ArrayView a, ArrayView b) noexcept
130+
requires requires (const T& x, const T& y) { { x == y } -> std::convertible_to<bool>; }
131+
{
132+
return a.size_ == b.size_ && std::equal(a.begin(), a.end(), b.begin());
133+
}
134+
135+
friend constexpr auto operator<=>(ArrayView a, ArrayView b) noexcept
136+
requires requires (const T& x, const T& y) { x <=> y; }
137+
{
138+
return std::lexicographical_compare_three_way(
139+
a.begin(), a.end(), b.begin(), b.end(), std::compare_three_way{});
140+
}
141+
142+
private:
143+
const T* data_ = nullptr;
144+
size_type size_ = 0;
145+
};
146+
147+
// deduction guides
148+
template <class T>
149+
ArrayView(const T*, std::size_t) -> ArrayView<T>;
150+
151+
template <class T, std::size_t N>
152+
ArrayView(const T (&)[N]) -> ArrayView<T>;
153+
154+
// helpers
155+
template <class T>
156+
constexpr ArrayView<T> make_array_view(const T* data, std::size_t count) noexcept {
157+
return ArrayView<T>(data, count);
158+
}
159+
160+
template <class T, std::size_t N>
161+
constexpr ArrayView<T> make_array_view(const T (&arr)[N]) noexcept {
162+
return ArrayView<T>(arr);
163+
}
164+
165+
} // mrdocs
166+
167+
#endif // MRDOCS_API_ADT_ARRAYVIEW_HPP

0 commit comments

Comments
 (0)