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*/
72
73/*!
74 \struct IR::InlineContent
75 \internal
76 \brief Represents inline content within a documentation block.
77
78 InlineContent is a format-agnostic representation of inline content
79 such as text, code, links, and formatting. Instances nest recursively
80 to represent formatting like bold text containing a link.
81
82 Each element is either a \e leaf (has \c text, no \c children) or a
83 \e container (has \c children, no \c text). This invariant is enforced
84 by Q_ASSERT in debug builds. Typically, content-bearing types such as
85 Text, Code, and Image are leaves, while formatting types such as Bold,
86 Italic, and Link are containers whose children carry the text.
87
88 The \c href and \c title fields are metadata that can be set on either
89 leaf or container elements (e.g., Link uses \c href with children;
90 Image uses \c href as a leaf).
91
92 This is a pure value type with no dependencies on QDoc's core
93 infrastructure. It belongs in QDocLib.
94
95 \sa ContentBlock, BlockType
96*/
97
98/*!
99 \struct IR::ContentBlock
100 \internal
101 \brief Represents a structural block element in documentation.
102
103 ContentBlock is a format-agnostic representation of documentation
104 structure. Each block is either a \e{leaf block} (has \c inlineContent,
105 no \c children) or a \e{container block} (has \c children, no
106 \c inlineContent). This invariant is enforced by Q_ASSERT in debug
107 builds. Typically, content-bearing blocks such as Paragraph, CodeBlock,
108 and SectionHeading are leaves, while structural blocks such as List,
109 Section, and callout blocks (Note, Warning, etc.) are containers.
110
111 The \c attributes field holds type-specific metadata as a QJsonObject.
112 Attribute keys use camelCase for compatibility with Inja dot notation
113 in templates (e.g., \c{block.attributes.listType}). Type IDs in the
114 \c type field use kebab-case (e.g., \c{"code-block"}).
115
116 This is a pure value type with no dependencies on QDoc's core
117 infrastructure. It belongs in QDocLib. Multiple renderers can read
118 the same ContentBlock concurrently — the frozen IR design supports
119 parallel rendering per output format.
120
121 \sa InlineContent, InlineType
122*/
123
124// Returns the kebab-case string ID for an InlineType.
126{
127 switch (type) {
128 case InlineType::Text: return u"text"_s;
129 case InlineType::Code: return u"code"_s;
130 case InlineType::Link: return u"link"_s;
131 case InlineType::Bold: return u"bold"_s;
132 case InlineType::Italic: return u"italic"_s;
133 case InlineType::Teletype: return u"teletype"_s;
134 case InlineType::Underline: return u"underline"_s;
135 case InlineType::Strikethrough: return u"strikethrough"_s;
136 case InlineType::Subscript: return u"subscript"_s;
137 case InlineType::Superscript: return u"superscript"_s;
138 case InlineType::Parameter: return u"parameter"_s;
139 case InlineType::LineBreak: return u"line-break"_s;
140 case InlineType::Image: return u"image"_s;
141 case InlineType::Keyword: return u"keyword"_s;
142 case InlineType::Target: return u"target"_s;
143 }
144 Q_UNREACHABLE();
145}
146
147// Returns the kebab-case string ID for a BlockType.
149{
150 switch (type) {
151 case BlockType::Paragraph: return u"paragraph"_s;
152 case BlockType::CodeBlock: return u"code-block"_s;
153 case BlockType::List: return u"list"_s;
154 case BlockType::ListItem: return u"list-item"_s;
155 case BlockType::Section: return u"section"_s;
156 case BlockType::SectionHeading: return u"section-heading"_s;
157 case BlockType::Note: return u"note"_s;
158 case BlockType::Warning: return u"warning"_s;
159 case BlockType::Important: return u"important"_s;
160 case BlockType::Details: return u"details"_s;
161 case BlockType::Brief: return u"brief"_s;
162 case BlockType::Div: return u"div"_s;
163 case BlockType::Quotation: return u"quotation"_s;
164 case BlockType::Legalese: return u"legalese"_s;
165 case BlockType::HorizontalRule: return u"horizontal-rule"_s;
166 case BlockType::Table: return u"table"_s;
167 case BlockType::TableRow: return u"table-row"_s;
168 case BlockType::TableHeaderRow: return u"table-header-row"_s;
169 case BlockType::TableCell: return u"table-cell"_s;
170 case BlockType::Raw: return u"raw"_s;
171 }
172 Q_UNREACHABLE();
173}
174
175/*!
176 Converts the InlineContent to a QJsonObject for template rendering.
177
178 The JSON uses kebab-case type IDs matching the convention in IR::Document
179 classification. Leaf elements (no children) include a \c text key with
180 their text content. Container elements (with children) omit \c text to
181 avoid redundancy — the text is available in their children.
182
183 Optional fields (\c href, \c title) are omitted when empty.
184 The \c children array is omitted when empty.
185*/
187{
188 Q_ASSERT(children.isEmpty() || text.isEmpty());
189
190 QJsonObject json;
191 json["type"_L1] = inlineTypeId(type);
192
193 if (children.isEmpty())
194 json["text"_L1] = plainText();
195
196 if (!href.isEmpty())
197 json["href"_L1] = href;
198 if (!title.isEmpty())
199 json["title"_L1] = title;
200
201 if (!children.isEmpty()) {
202 QJsonArray arr;
203 for (const auto &child : children)
204 arr.append(child.toJson());
205 json["children"_L1] = arr;
206 }
207
208 if (!attributes.isEmpty())
209 json["attributes"_L1] = attributes;
210
211 return json;
212}
213
214/*!
215 Returns the concatenated plain text of this inline element and all its
216 children, recursively.
217
218 For leaf elements (Text, Code, Keyword, Target, Parameter, Image),
219 returns the \c text field. For LineBreak, returns a newline character.
220 For container elements (Bold, Italic, Link, etc.), concatenates the
221 plain text of all children.
222*/
224{
225 Q_ASSERT(children.isEmpty() || text.isEmpty());
226 if (type == InlineType::LineBreak)
227 return u"\n"_s;
228
229 if (!children.isEmpty()) {
230 QStringList parts;
231 parts.reserve(children.size());
232 for (const auto &child : children)
233 parts.append(child.plainText());
234 return parts.join(u""_s);
235 }
236
237 return text;
238}
239
240/*!
241 Converts the ContentBlock to a QJsonObject for template rendering.
242
243 The JSON uses kebab-case type IDs. A computed \c text key contains the
244 concatenated plain text of all inline content or children. Empty
245 collections (\c inlines, \c children, \c attributes) are omitted.
246*/
248{
249 Q_ASSERT(inlineContent.isEmpty() || children.isEmpty());
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 if (!children.isEmpty()) {
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 inline content or
283 child blocks, recursively.
284
285 For leaf blocks with inline content (paragraphs, headings), concatenates
286 all inline text. For container blocks (lists, sections), concatenates
287 the plain text of child blocks separated by newlines.
288*/
290{
291 Q_ASSERT(inlineContent.isEmpty() || children.isEmpty());
292 if (!inlineContent.isEmpty()) {
293 QStringList parts;
294 parts.reserve(inlineContent.size());
295 for (const auto &inline_ : inlineContent)
296 parts.append(inline_.plainText());
297 return parts.join(u""_s);
298 }
299
300 if (!children.isEmpty()) {
301 QStringList parts;
302 parts.reserve(children.size());
303 for (const auto &child : children)
304 parts.append(child.plainText());
305 return parts.join(u"\n"_s);
306 }
307
308 return {};
309}
310
311} // namespace IR
312
313QT_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 inline content or child blocks,...
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.