Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
contentblock.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "contentblock.h"
5
6#include <QJsonArray>
7#include <QStringList>
8
10
11using namespace Qt::Literals::StringLiterals;
12
13namespace IR {
14
15/*!
16 \enum IR::InlineType
17 \internal
18 \brief Discriminator for inline content elements within a block.
19
20 Inline types represent formatting and content that flows within a block
21 element (paragraph, heading, etc.). They can nest — for example, Bold
22 containing Text, or Link containing Code.
23
24 \value Text Plain text content.
25 \value Code Inline code span, such as a class or function name.
26 \value Link Hyperlink to another page or external resource.
27 \value Bold Bold-formatted text.
28 \value Italic Italic-formatted text.
29 \value Teletype Monospaced text, typically rendered as \c{<tt>}.
30 \value Underline Underlined text.
31 \value Strikethrough Struck-through text.
32 \value Subscript Subscript text.
33 \value Superscript Superscript text.
34 \value Parameter Function parameter name.
35 \value LineBreak Explicit line break within a block.
36 \value Image Inline image.
37 \value Keyword Index keyword anchor.
38 \value Target Named anchor target for cross-references.
39*/
40
41/*!
42 \enum IR::BlockType
43 \internal
44 \brief Discriminator for structural block elements in documentation.
45
46 Block types represent the structural elements of documentation content:
47 paragraphs, code blocks, lists, sections, and callout blocks. They nest
48 to form the document structure (e.g., List containing ListItems, each
49 containing Paragraphs).
50
51 \value Paragraph A paragraph of text with inline content.
52 \value CodeBlock A block of source code, optionally with a language attribute.
53 \value List An ordered or unordered list containing ListItem children.
54 \value ListItem A single item within a List.
55 \value Section A document section containing a heading and child blocks.
56 \value SectionHeading A section heading with a level attribute (1–6).
57 \value Note A note callout block.
58 \value Warning A warning callout block.
59 \value Important An important callout block.
60 \value Details A collapsible details block.
61 \value Brief The brief description of a documented entity.
62 \value Div A generic container block.
63 \value Quotation A block quotation.
64 \value Legalese A legal text block, such as a license notice.
65 \value HorizontalRule A horizontal separator rule.
66 \value Table A table container with TableRow and TableHeaderRow children.
67 \value TableRow A data row within a table, containing TableCell children.
68 \value TableHeaderRow A header row within a table, containing header cells.
69 \value TableCell A cell within a table row.
70 \value Raw Raw format-specific content passed through without processing.
71 \value DefinitionList A definition or value list containing DefinitionTerm and DefinitionDescription pairs.
72 \value DefinitionTerm The term or key in a definition list entry.
73 \value DefinitionDescription The description or value in a definition list entry.
74*/
75
76/*!
77 \struct IR::InlineContent
78 \internal
79 \brief Represents inline content within a documentation block.
80
81 InlineContent is a format-agnostic representation of inline content
82 such as text, code, links, and formatting. Instances nest recursively
83 to represent formatting like bold text containing a link.
84
85 Each element is either a \e leaf (has \c text, no \c children) or a
86 \e container (has \c children, no \c text). This invariant is enforced
87 by Q_ASSERT in debug builds. Typically, content-bearing types such as
88 Text, Code, and Image are leaves, while formatting types such as Bold,
89 Italic, and Link are containers whose children carry the text.
90
91 The \c href and \c title fields are metadata that can be set on either
92 leaf or container elements (e.g., Link uses \c href with children;
93 Image uses \c href as a leaf).
94
95 This is a pure value type with no dependencies on QDoc's core
96 infrastructure. It belongs in QDocLib.
97
98 \sa ContentBlock, BlockType
99*/
100
101/*!
102 \struct IR::ContentBlock
103 \internal
104 \brief Represents a structural block element in documentation.
105
106 ContentBlock is a format-agnostic representation of documentation
107 structure. Most blocks are either \e{leaf blocks} (with \c inlineContent)
108 or \e{container blocks} (with \c children). Some atom chains produce
109 blocks that mix both — serialization and plainText() handle this
110 gracefully.
111
112 The \c attributes field holds type-specific metadata as a QJsonObject.
113 Attribute keys use camelCase for compatibility with Inja dot notation
114 in templates (e.g., \c{block.attributes.listType}). Type IDs in the
115 \c type field use kebab-case (e.g., \c{"code-block"}).
116
117 This is a pure value type with no dependencies on QDoc's core
118 infrastructure. It belongs in QDocLib. Multiple renderers can read
119 the same ContentBlock concurrently — the frozen IR design supports
120 parallel rendering per output format.
121
122 \sa InlineContent, InlineType
123*/
124
125// Returns the kebab-case string ID for an InlineType.
127{
128 switch (type) {
129 case InlineType::Text: return u"text"_s;
130 case InlineType::Code: return u"code"_s;
131 case InlineType::Link: return u"link"_s;
132 case InlineType::Bold: return u"bold"_s;
133 case InlineType::Italic: return u"italic"_s;
134 case InlineType::Teletype: return u"teletype"_s;
135 case InlineType::Underline: return u"underline"_s;
136 case InlineType::Strikethrough: return u"strikethrough"_s;
137 case InlineType::Subscript: return u"subscript"_s;
138 case InlineType::Superscript: return u"superscript"_s;
139 case InlineType::Parameter: return u"parameter"_s;
140 case InlineType::LineBreak: return u"line-break"_s;
141 case InlineType::Image: return u"image"_s;
142 case InlineType::Keyword: return u"keyword"_s;
143 case InlineType::Target: return u"target"_s;
144 }
145 Q_UNREACHABLE();
146}
147
148// Returns the kebab-case string ID for a BlockType.
150{
151 switch (type) {
152 case BlockType::Paragraph: return u"paragraph"_s;
153 case BlockType::CodeBlock: return u"code-block"_s;
154 case BlockType::List: return u"list"_s;
155 case BlockType::ListItem: return u"list-item"_s;
156 case BlockType::Section: return u"section"_s;
157 case BlockType::SectionHeading: return u"section-heading"_s;
158 case BlockType::Note: return u"note"_s;
159 case BlockType::Warning: return u"warning"_s;
160 case BlockType::Important: return u"important"_s;
161 case BlockType::Details: return u"details"_s;
162 case BlockType::Brief: return u"brief"_s;
163 case BlockType::Div: return u"div"_s;
164 case BlockType::Quotation: return u"quotation"_s;
165 case BlockType::Legalese: return u"legalese"_s;
166 case BlockType::HorizontalRule: return u"horizontal-rule"_s;
167 case BlockType::Table: return u"table"_s;
168 case BlockType::TableRow: return u"table-row"_s;
169 case BlockType::TableHeaderRow: return u"table-header-row"_s;
170 case BlockType::TableCell: return u"table-cell"_s;
171 case BlockType::Raw: return u"raw"_s;
172 case BlockType::DefinitionList: return u"definition-list"_s;
173 case BlockType::DefinitionTerm: return u"definition-term"_s;
174 case BlockType::DefinitionDescription: return u"definition-description"_s;
175 }
176 Q_UNREACHABLE();
177}
178
179/*!
180 Converts the InlineContent to a QJsonObject for template rendering.
181
182 The JSON uses kebab-case type IDs matching the convention in IR::Document
183 classification. Every element includes a \c text key: leaf elements use
184 their text field directly, while container elements produce a flattened
185 plain-text concatenation of their children. This ensures templates can
186 always access \c text without checking whether the element is a leaf or
187 container.
188
189 Optional fields (\c href, \c title) are omitted when empty.
190 The \c children array is omitted when empty.
191*/
193{
194 Q_ASSERT(children.isEmpty() || text.isEmpty());
195
196 QJsonObject json;
197 json["type"_L1] = inlineTypeId(type);
198 json["text"_L1] = plainText();
199
200 if (!href.isEmpty())
201 json["href"_L1] = href;
202 if (!title.isEmpty())
203 json["title"_L1] = title;
204
205 QJsonArray childArr;
206 for (const auto &child : children)
207 childArr.append(child.toJson());
208 json["children"_L1] = childArr;
209
210 if (!attributes.isEmpty())
211 json["attributes"_L1] = attributes;
212
213 return json;
214}
215
216/*!
217 Returns the concatenated plain text of this inline element and all its
218 children, recursively.
219
220 For leaf elements (Text, Code, Keyword, Target, Parameter, Image),
221 returns the \c text field. For LineBreak, returns a newline character.
222 For container elements (Bold, Italic, Link, etc.), concatenates the
223 plain text of all children.
224*/
226{
227 Q_ASSERT(children.isEmpty() || text.isEmpty());
228 if (type == InlineType::LineBreak)
229 return u"\n"_s;
230
231 if (!children.isEmpty()) {
232 QStringList parts;
233 parts.reserve(children.size());
234 for (const auto &child : children)
235 parts.append(child.plainText());
236 return parts.join(u""_s);
237 }
238
239 return text;
240}
241
242/*!
243 Converts the ContentBlock to a QJsonObject for template rendering.
244
245 The JSON uses kebab-case type IDs. A computed \c text key contains the
246 concatenated plain text of all inline content or children. Empty
247 collections (\c inlines, \c children, \c attributes) are omitted.
248*/
250{
251 QJsonObject json;
252 json["type"_L1] = blockTypeId(type);
253 json["text"_L1] = plainText();
254
255 if (!attributes.isEmpty())
256 json["attributes"_L1] = attributes;
257
258 if (!inlineContent.isEmpty()) {
259 QJsonArray arr;
260 for (const auto &inline_ : inlineContent)
261 arr.append(inline_.toJson());
262 json["inlines"_L1] = arr;
263 }
264
265 {
266 QJsonArray arr;
267 for (const auto &child : children)
268 arr.append(child.toJson());
269
270 if (type == BlockType::Table)
271 json["rows"_L1] = arr;
272 else if (type == BlockType::TableRow || type == BlockType::TableHeaderRow)
273 json["cells"_L1] = arr;
274 else
275 json["children"_L1] = arr;
276 }
277
278 return json;
279}
280
281/*!
282 Returns the concatenated plain text of this block's content,
283 recursively. Collects inline text first, then child block text.
284 Blocks may have both inline content and children when the atom
285 chain mixes inline and block-level elements within the same
286 container.
287*/
289{
290 QStringList parts;
291
292 if (!inlineContent.isEmpty()) {
293 parts.reserve(inlineContent.size());
294 for (const auto &inline_ : inlineContent)
295 parts.append(inline_.plainText());
296 }
297
298 if (!children.isEmpty()) {
299 QStringList childParts;
300 for (const auto &child : children)
301 childParts.append(child.plainText());
302 if (!parts.isEmpty())
303 parts.append(u"\n"_s);
304 parts.append(childParts.join(u"\n"_s));
305 }
306
307 return parts.join(u""_s);
308}
309
310} // namespace IR
311
312QT_END_NAMESPACE
Definition builder.cpp:14
static QString inlineTypeId(InlineType type)
static QString blockTypeId(BlockType type)
BlockType
InlineType
Combined button and popup list for selecting options.
Represents a structural block element in documentation.
QJsonObject toJson() const
Converts the ContentBlock to a QJsonObject for template rendering.
QString plainText() const
Returns the concatenated plain text of this block's content, recursively.
Represents inline content within a documentation block.
QJsonObject toJson() const
Converts the InlineContent to a QJsonObject for template rendering.
QString plainText() const
Returns the concatenated plain text of this inline element and all its children, recursively.