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
contentbuilder.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
5
6#include "../atom.h"
7#include "../tree.h"
8
10
11using namespace Qt::Literals::StringLiterals;
12
13static QString stripCodeMarkerTags(const QString &markedCode)
14{
15 static const QRegularExpression tag(u"</?@[^>]*>"_s);
16 QString t = markedCode;
17 t.replace(tag, QString());
18 t.replace(u"&quot;"_s, u"\""_s);
19 t.replace(u"&gt;"_s, u">"_s);
20 t.replace(u"&lt;"_s, u"<"_s);
21 t.replace(u"&amp;"_s, u"&"_s);
22 return t;
23}
24
25static QString genusToString(Genus genus)
26{
27 switch (genus) {
28 case Genus::CPP: return u"cpp"_s;
29 case Genus::QML: return u"qml"_s;
30 case Genus::DOC: return u"doc"_s;
31 case Genus::API: return u"api"_s;
32 case Genus::DontCare: return {};
33 }
34 return {};
35}
36
37namespace IR {
38
39/*!
40 \class IR::ContentBuilder
41 \internal
42 \brief Converts Atom chains to QList<IR::ContentBlock> trees.
43
44 ContentBuilder walks a linked list of Atom nodes (QDoc's internal
45 documentation representation) and produces a structured tree of
46 ContentBlock and InlineContent values suitable for template rendering.
47
48 Handled atom types:
49 \list
50 \li ParaLeft, ParaRight -- Paragraph blocks.
51 \li String -- Text inline content.
52 \li C -- Inline code spans.
53 \li Code, CodeBad, Qml -- Code blocks with language attribute.
54 \li SectionLeft, SectionRight -- Section containers.
55 \li SectionHeadingLeft, SectionHeadingRight -- Section headings with
56 level.
57 \li FormattingLeft, FormattingRight -- Bold, italic, teletype,
58 underline, subscript, superscript, parameter, uicontrol, trademark,
59 link, index, notranslate, span.
60 \li ListLeft, ListRight -- Ordered and unordered lists.
61 \li ListItemLeft, ListItemRight -- List items.
62 \li ListItemNumber -- List start number metadata.
63 \li NoteLeft, NoteRight -- Note admonition blocks.
64 \li WarningLeft, WarningRight -- Warning admonition blocks.
65 \li BriefLeft, BriefRight -- Brief exclusion (skipped by default,
66 or emitted as Paragraph with BriefHandling::Include).
67 \li Link, NavLink -- Explicit links with unresolved target.
68 \li AutoLink, NavAutoLink -- Auto-linked type names with unresolved
69 target.
70 \li BR -- Line break inline.
71 \li HR -- Horizontal rule block.
72 \li Nop -- No-operation (skipped).
73 \li BaseName -- No-operation (skipped).
74 \li TableLeft, TableRight -- Table containers with style attribute.
75 \li TableHeaderLeft, TableHeaderRight -- Table header rows.
76 \li TableRowLeft, TableRowRight -- Table data rows.
77 \li TableItemLeft, TableItemRight -- Table cells with optional
78 colspan/rowspan.
79 \li Image -- Block-level image (wrapping Paragraph with centerAlign).
80 \li InlineImage -- Inline image within a paragraph.
81 \li ImageText -- Alt text consumed by the preceding Image or
82 InlineImage handler.
83 \li ListTagLeft, ListTagRight -- Value list tag items (ListItem
84 blocks).
85 \li SinceTagLeft, SinceTagRight -- Version tag items (skipped).
86 \li AnnotatedList -- Placeholder Div.
87 \li GeneratedList -- Placeholder Div.
88 \endlist
89
90 Format-conditional atoms (FormatIf, FormatElse, FormatEndif) are
91 skipped unconditionally. The template generator builds a
92 format-agnostic IR that serves all output formats from a single
93 build pass.
94
95 The optional BriefHandling parameter controls whether brief
96 content (between BriefLeft and BriefRight atoms) is included in
97 the output. The default is BriefHandling::Skip, which suppresses
98 brief content. BriefHandling::Include causes brief content to be
99 emitted as a Paragraph block.
100
101 ContentBuilder depends only on Atom (for reading the chain) and IR types
102 (for producing output).
103
104 \sa ContentBlock, InlineContent
105*/
106
107/*!
108 Constructs a ContentBuilder.
109
110 The \a briefHandling parameter controls whether content between
111 BriefLeft and BriefRight atoms is emitted as a Paragraph block
112 (BriefHandling::Include) or suppressed (BriefHandling::Skip).
113
114 The \a headingOffset parameter shifts section heading levels to
115 account for the page structure. QDoc's \\section1 maps to level 1,
116 but pages already use \c{<h1>} for the title and \c{<h2>} for
117 major sections. The legacy generators apply an offset derived from
118 the node type; callers pass that same offset here so the IR
119 produces correct heading levels without depending on \b Node.
120*/
121ContentBuilder::ContentBuilder(BriefHandling briefHandling, int headingOffset,
122 DiagnosticHandler diagnosticHandler)
123 : m_briefHandling(briefHandling), m_headingOffset(headingOffset),
125{
126}
127
128static InlineType formattingToInlineType(const QString &formatting)
129{
130 if (formatting == ATOM_FORMATTING_BOLD)
131 return InlineType::Bold;
132 if (formatting == ATOM_FORMATTING_ITALIC)
133 return InlineType::Italic;
134 if (formatting == ATOM_FORMATTING_TELETYPE)
136 if (formatting == ATOM_FORMATTING_UNDERLINE)
138 if (formatting == ATOM_FORMATTING_SUBSCRIPT)
140 if (formatting == ATOM_FORMATTING_SUPERSCRIPT)
142 if (formatting == ATOM_FORMATTING_PARAMETER)
144 return InlineType::Text;
145}
146
147/*!
148 Walks the atom chain starting at \a firstAtom and returns a list
149 of ContentBlock trees representing the structured documentation body.
150
151 Returns an empty list if \a firstAtom is \nullptr.
152
153 The builder is reset before processing, so a single ContentBuilder
154 instance can be reused for multiple build() calls.
155*/
157{
158 m_result.clear();
159 m_blockPath.clear();
160 m_inlinePath.clear();
161 m_inlineBaseDepths.clear();
162 m_inBrief = false;
163 m_inLink = false;
164
165 if (!firstAtom)
166 return {};
167
168 processAtoms(firstAtom);
169
170 // Malformed atom chain recovery: auto-close remaining blocks in
171 // release builds, assert in debug to surface the source error.
172 while (!m_blockPath.isEmpty())
173 closeBlock();
174 m_inlinePath.clear();
175 m_inlineBaseDepths.clear();
176 m_inLink = false;
177 m_inBrief = false;
178
179 return m_result;
180}
181
182/*!
183 Walks the full atom chain starting at \a atom, building the
184 content tree. FormatIf..FormatEndif blocks are skipped
185 unconditionally via skipFormatIfBlock(). Stray FormatElse and
186 FormatEndif atoms outside any FormatIf context are ignored.
187*/
188void ContentBuilder::processAtoms(const Atom *atom)
189{
190 while (atom) {
191 if (atom->type() == Atom::FormatIf) {
192 atom = skipFormatIfBlock(atom);
193 continue;
194 }
196 atom = atom->next();
197 continue;
198 }
199 atom = dispatchAtom(atom);
200 if (!atom)
201 return;
202 atom = atom->next();
203 }
204}
205
206/*!
207 Skips an entire FormatIf..FormatEndif block, including any nested
208 FormatIf blocks and FormatElse branches. The scan only tracks
209 FormatIf and FormatEndif for depth counting; all other atom types
210 (including FormatElse) are treated as inert content and walked
211 past without dispatch.
212
213 The template generator builds a format-agnostic IR, so
214 format-conditional content is unconditionally excluded.
215
216 Returns a pointer to the atom after FormatEndif, or \nullptr if
217 the chain ends before FormatEndif is found.
218*/
219const Atom *ContentBuilder::skipFormatIfBlock(const Atom *atom)
220{
221 Q_ASSERT(atom->type() == Atom::FormatIf);
222 int depth = 1;
223 atom = atom->next();
224 while (atom && depth > 0) {
225 if (atom->type() == Atom::FormatIf)
226 ++depth;
227 else if (atom->type() == Atom::FormatEndif)
228 --depth;
229 atom = atom->next();
230 }
231 return atom;
232}
233
234/*!
235 Dispatches a single atom to the content model. Returns the last
236 atom consumed — usually \a atom itself, but some atom types may
237 consume subsequent atoms.
238*/
239const Atom *ContentBuilder::dispatchAtom(const Atom *atom)
240{
241 if (atom->type() == Atom::BriefLeft) {
242 m_inBrief = true;
243 if (m_briefHandling == BriefHandling::Include)
244 openBlock(BlockType::Paragraph);
245 return atom;
246 }
247 if (atom->type() == Atom::BriefRight) {
248 if (m_briefHandling == BriefHandling::Include)
249 closeBlock();
250 m_inBrief = false;
251 return atom;
252 }
253 if (m_inBrief && m_briefHandling != BriefHandling::Include)
254 return atom;
255
256 switch (atom->type()) {
257
258 case Atom::ParaLeft:
259 openBlock(BlockType::Paragraph);
260 break;
261
262 case Atom::ParaRight:
263 closeBlock();
264 break;
265
266 case Atom::String:
267 addLeafInline(InlineType::Text, atom->string());
268 break;
269
270 case Atom::C:
271 addLeafInline(InlineType::Code, stripCodeMarkerTags(atom->string()));
272 break;
273
274 case Atom::Code:
275 case Atom::CodeBad:
276 case Atom::Qml: {
277 QJsonObject attrs;
278 if (atom->type() == Atom::Qml) {
279 attrs["language"_L1] = u"qml"_s;
280 } else if (atom->type() == Atom::CodeBad) {
281 attrs["language"_L1] = u"cpp"_s;
282 attrs["bad"_L1] = true;
283 } else if (atom->count() >= 2 && !atom->string(1).isEmpty()) {
284 attrs["language"_L1] = atom->string(1);
285 } else {
286 attrs["language"_L1] = u"cpp"_s;
287 }
288
289 openBlock(BlockType::CodeBlock, attrs);
290 addLeafInline(InlineType::Text, stripCodeMarkerTags(atom->string()));
291 closeBlock();
292 break;
293 }
294
295 case Atom::AutoLink:
296 case Atom::NavAutoLink: {
297 // href values are not author-controlled. They are produced by QDoc
298 // link resolution (\l, autolinks) against the node tree, or by
299 // \image path handling. They don't contain arbitrary schemes (e.g.
300 // javascript:). Only link text originates from user-authored docs
301 // and must be HTML-escaped in templates.
302 InlineContent link;
304 link.href = atom->string();
306 link.children.append({ InlineType::Text, atom->string(), {}, {}, {}, {}, {} });
307 addInline(std::move(link));
308 break;
309 }
310
311 case Atom::Link:
312 case Atom::NavLink: {
313 if (m_blockPath.isEmpty())
314 openBlock(BlockType::Paragraph);
315
316 m_inLink = true;
317
318 InlineContent link;
320 link.href = atom->string();
322
323 // Extract genus and module scope from LinkAtom if available.
324 if (atom->isLinkAtom()) {
325 // genus() and domain() are non-const but non-mutating;
326 // the same const_cast pattern is used in qdocdatabase.cpp.
327 auto *mutableAtom = const_cast<Atom *>(atom);
328 Genus genus = mutableAtom->genus();
329 QString genusStr = genusToString(genus);
330 if (!genusStr.isEmpty())
331 link.attributes["linkGenus"_L1] = genusStr;
332 if (Tree *domain = mutableAtom->domain())
333 link.attributes["linkModule"_L1] = domain->physicalModuleName();
334 }
335
336 pushInlineContainer(std::move(link));
337
338 // Link atoms are always followed by FormattingLeft("link");
339 // skip it to avoid double-processing.
341 && atom->next()->string() == ATOM_FORMATTING_LINK) {
342 return atom->next();
343 }
344 break;
345 }
346
348 const QString &fmt = atom->string();
349
350 if (fmt == ATOM_FORMATTING_INDEX || fmt.startsWith(u"span "_s))
351 break;
352
353 if (fmt == ATOM_FORMATTING_LINK)
354 break;
355
357 break;
358
359 if (fmt == ATOM_FORMATTING_UICONTROL) {
360 InlineContent bold;
362 pushInlineContainer(std::move(bold));
363 break;
364 }
365
366 InlineType type = formattingToInlineType(fmt);
367 if (type == InlineType::Text)
368 break;
369
370 InlineContent container;
371 container.type = type;
372 pushInlineContainer(std::move(container));
373 break;
374 }
375
377 const QString &fmt = atom->string();
378
379 if (fmt == ATOM_FORMATTING_LINK) {
380 if (m_inLink) {
381 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
382 if (m_inlinePath.size() > base) {
383 Q_ASSERT(resolveInline()->type == InlineType::Link);
384 m_inlinePath.removeLast();
385 }
386 m_inLink = false;
387 }
388 break;
389 }
390
392 || fmt.startsWith(u"span "_s) || fmt == ATOM_FORMATTING_TRADEMARK) {
393 break;
394 }
395
396 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
397 if (m_inlinePath.size() > base)
398 m_inlinePath.removeLast();
399 break;
400 }
401
402 case Atom::SectionLeft:
403 openBlock(BlockType::Section);
404 break;
405
407 closeBlock();
408 break;
409
411 QJsonObject attrs;
412 attrs["level"_L1] = atom->string().toInt() + m_headingOffset;
413 openBlock(BlockType::SectionHeading, attrs);
414 break;
415 }
416
418 closeBlock();
419 break;
420
421 case Atom::ListLeft: {
422 QJsonObject attrs;
423 const QString &listType = atom->string();
424 attrs["listType"_L1] = listType;
425 if (listType == ATOM_LIST_TAG || listType == ATOM_LIST_VALUE)
426 openBlock(BlockType::DefinitionList, attrs);
427 else
428 openBlock(BlockType::List, attrs);
429 break;
430 }
431
432 case Atom::ListRight:
433 closeBlock();
434 break;
435
436 case Atom::ListItemLeft: {
437 ContentBlock *parent = resolveBlock();
438 if (parent->type == BlockType::DefinitionList)
439 openBlock(BlockType::DefinitionDescription);
440 else
441 openBlock(BlockType::ListItem);
442 break;
443 }
444
446 closeBlock();
447 break;
448
450 // Start-number metadata is not yet represented in the IR.
451 break;
452
453 case Atom::NoteLeft:
454 openBlock(BlockType::Note);
455 break;
456
457 case Atom::NoteRight:
458 closeBlock();
459 break;
460
461 case Atom::WarningLeft:
462 openBlock(BlockType::Warning);
463 break;
464
466 closeBlock();
467 break;
468
469 case Atom::BR:
470 addLeafInline(InlineType::LineBreak, {});
471 break;
472
473 case Atom::HR:
474 openBlock(BlockType::HorizontalRule);
475 closeBlock();
476 break;
477
478 case Atom::AnnotatedList: {
479 QJsonObject attrs;
480 attrs["annotatedList"_L1] = atom->string();
481 openBlock(BlockType::Div, attrs);
482 closeBlock();
483 break;
484 }
485
486 case Atom::GeneratedList: {
487 QJsonObject attrs;
488 attrs["generatedList"_L1] = atom->string();
489 openBlock(BlockType::Div, attrs);
490 closeBlock();
491 break;
492 }
493
494 case Atom::TableLeft: {
495 QJsonObject attrs;
496 QString tableStyle = u"generic"_s;
497 QString width;
498
499 for (int i = 0; i < atom->count(); ++i) {
500 const QString &arg = atom->string(i);
501 if (arg == "borderless"_L1)
502 tableStyle = arg;
503 else if (arg.contains('%'_L1))
504 width = arg;
505 }
506
507 // Handle "100 %" (space before percent) — the percent arrives
508 // as a separate atom argument, reconstruct the width value.
509 if (width == "%"_L1) {
510 bool ok = false;
511 int pct = atom->string(0).toInt(&ok);
512 width = ok ? QString::number(pct) + '%'_L1 : QString();
513 }
514
515 attrs["style"_L1] = tableStyle;
516 if (!width.isEmpty())
517 attrs["width"_L1] = width;
518 openBlock(BlockType::Table, attrs);
519 break;
520 }
521
522 case Atom::TableRight:
523 closeBlock();
524 break;
525
526 case Atom::TableHeaderLeft:
527 openBlock(BlockType::TableHeaderRow);
528 break;
529
531 closeBlock();
532 break;
533
534 case Atom::TableRowLeft:
535 openBlock(BlockType::TableRow);
536 break;
537
539 closeBlock();
540 break;
541
542 case Atom::TableItemLeft: {
543 QJsonObject attrs;
544 const QString &spec = atom->string();
545 if (!spec.isEmpty()) {
546 const auto parts = QStringView{spec}.split(u',');
547 if (parts.size() >= 2) {
548 int colspan = qMax(1, parts[0].toInt());
549 int rowspan = qMax(1, parts[1].toInt());
550 if (colspan > 1)
551 attrs["colspan"_L1] = colspan;
552 if (rowspan > 1)
553 attrs["rowspan"_L1] = rowspan;
554 }
555 }
556 openBlock(BlockType::TableCell, attrs);
557 break;
558 }
559
561 closeBlock();
562 break;
563
564 case Atom::ListTagLeft:
565 openBlock(BlockType::DefinitionTerm);
566 break;
567
569 closeBlock();
570 break;
571
572 case Atom::Image: {
573 QJsonObject attrs;
574 attrs["class"_L1] = u"centerAlign"_s;
575 openBlock(BlockType::Paragraph, attrs);
576
577 InlineContent img;
579 img.href = atom->string();
580 if (atom->next() && atom->next()->type() == Atom::ImageText)
581 img.title = atom->next()->string();
582 addInline(std::move(img));
583
584 closeBlock();
585
586 if (atom->next() && atom->next()->type() == Atom::ImageText)
587 return atom->next();
588 break;
589 }
590
591 case Atom::InlineImage: {
592 if (Q_UNLIKELY(m_blockPath.isEmpty()))
593 break;
594
595 InlineContent img;
597 img.href = atom->string();
598 if (atom->next() && atom->next()->type() == Atom::ImageText)
599 img.title = atom->next()->string();
600 addInline(std::move(img));
601
602 if (atom->next() && atom->next()->type() == Atom::ImageText)
603 return atom->next();
604 break;
605 }
606
607 case Atom::ImageText:
608 break;
609
612 break;
613
614 case Atom::Nop:
615 case Atom::BaseName:
616 break;
617
618 default:
619 break;
620 }
621 return atom;
622}
623
624/*!
625 Opens a new block of type \a type with optional \a attrs.
626
627 If the block path is empty, the block is added to the top-level
628 result list. Otherwise it is added as a child of the current
629 container block.
630*/
631void ContentBuilder::openBlock(BlockType type, QJsonObject attrs)
632{
633 ContentBlock block;
634 block.type = type;
635 block.attributes = std::move(attrs);
636
637 m_inlineBaseDepths.append(m_inlinePath.size());
638
639 if (m_blockPath.isEmpty()) {
640 m_result.append(std::move(block));
641 m_blockPath.append(m_result.size() - 1);
642 } else {
643 auto *parent = resolveBlock();
644 parent->children.append(std::move(block));
645 m_blockPath.append(parent->children.size() - 1);
646 }
647}
648
649/*!
650 Closes the current block by popping it from the block path.
651
652 Verifies that the inline path depth matches the depth recorded
653 when this block was opened (all formatting pairs balanced).
654 In release builds, the inline path is restored to the expected
655 depth as a safety measure against malformed atom chains.
656*/
657void ContentBuilder::closeBlock()
658{
659 if (!m_blockPath.isEmpty()) {
660 if (Q_UNLIKELY(m_inlineBaseDepths.isEmpty())) {
661 m_inlinePath.clear();
662 m_blockPath.clear();
663 m_inlineBaseDepths.clear();
664 m_inLink = false;
665 return;
666 }
667 const qsizetype expectedDepth = m_inlineBaseDepths.last();
668 if (m_inLink && m_inlinePath.size() > expectedDepth)
669 m_inLink = false;
670 m_inlinePath.resize(expectedDepth);
671 m_inlinePath.resize(expectedDepth);
672 m_inlineBaseDepths.removeLast();
673 m_blockPath.removeLast();
674 }
675}
676
677/*!
678 Adds \a inline_ to the current block's inline content.
679
680 If there is an active inline container (from FormattingLeft or
681 Link atom), the inline is added to that container's children
682 instead.
683
684 If no block is open, the inline is dropped. This shouldn't happen
685 with well-formed atom chains (text is always wrapped in
686 ParaLeft/ParaRight), and is asserted in debug builds.
687*/
688void ContentBuilder::addInline(InlineContent inline_)
689{
690 if (!m_inlinePath.isEmpty()) {
691 resolveInline()->children.append(std::move(inline_));
692 } else if (!m_blockPath.isEmpty()) {
693 resolveBlock()->inlineContent.append(std::move(inline_));
694 } else {
695 if (m_diagnose)
696 m_diagnose(QtWarningMsg, u"Dropping inline content outside any block"_s);
697 }
698}
699
700/*!
701 Convenience method: creates a leaf InlineContent of the given
702 \a type with \a text and appends it via addInline().
703*/
704void ContentBuilder::addLeafInline(InlineType type, const QString &text)
705{
706 InlineContent ic;
707 ic.type = type;
708 ic.text = text;
709 addInline(std::move(ic));
710}
711
712/*!
713 Pushes \a container as a new inline container. Subsequent
714 addInline() and pushInlineContainer() calls will nest
715 their content inside this container.
716
717 Unlike addInline(), which only appends leaf inlines, this method
718 also updates m_inlinePath to enable nesting. It respects the
719 existing inline path: if we are already inside a Link or formatting
720 container, the new container is added as a child of that container.
721*/
722void ContentBuilder::pushInlineContainer(InlineContent container)
723{
724 if (!m_inlinePath.isEmpty()) {
725 auto *parent = resolveInline();
726 parent->children.append(std::move(container));
727 m_inlinePath.append(parent->children.size() - 1);
728 } else if (!m_blockPath.isEmpty()) {
729 auto *block = resolveBlock();
730 block->inlineContent.append(std::move(container));
731 m_inlinePath.append(block->inlineContent.size() - 1);
732 }
733}
734
735/*!
736 Resolves the current block path to a ContentBlock pointer.
737
738 The returned pointer is valid only until the next QList mutation
739 on any list in the path. Callers must use the pointer within a
740 single expression and discard it before appending to any QList.
741*/
742ContentBlock *ContentBuilder::resolveBlock()
743{
744 Q_ASSERT(!m_blockPath.isEmpty());
745 Q_ASSERT(m_blockPath[0] >= 0 && m_blockPath[0] < m_result.size());
746 ContentBlock *block = &m_result[m_blockPath[0]];
747 for (qsizetype i = 1; i < m_blockPath.size(); ++i) {
748 Q_ASSERT(m_blockPath[i] >= 0 && m_blockPath[i] < block->children.size());
749 block = &block->children[m_blockPath[i]];
750 }
751 return block;
752}
753
754/*!
755 Resolves the current inline path to an InlineContent pointer.
756
757 Walks the block path first (via resolveBlock()), then descends
758 through the block's inlineContent and nested children lists
759 using the indices in m_inlinePath.
760*/
761InlineContent *ContentBuilder::resolveInline()
762{
763 ContentBlock *block = resolveBlock();
764 Q_ASSERT(!m_inlinePath.isEmpty());
765 Q_ASSERT(m_inlinePath[0] >= 0 && m_inlinePath[0] < block->inlineContent.size());
766 InlineContent *ic = &block->inlineContent[m_inlinePath[0]];
767 for (qsizetype i = 1; i < m_inlinePath.size(); ++i) {
768 Q_ASSERT(m_inlinePath[i] >= 0 && m_inlinePath[i] < ic->children.size());
769 ic = &ic->children[m_inlinePath[i]];
770 }
771 return ic;
772}
773
774} // namespace IR
775
776QT_END_NAMESPACE
#define ATOM_FORMATTING_TELETYPE
Definition atom.h:213
#define ATOM_FORMATTING_UNDERLINE
Definition atom.h:216
#define ATOM_FORMATTING_NOTRANSLATE
Definition atom.h:208
#define ATOM_LIST_TAG
Definition atom.h:219
#define ATOM_FORMATTING_SUBSCRIPT
Definition atom.h:211
#define ATOM_FORMATTING_BOLD
Definition atom.h:204
#define ATOM_FORMATTING_TRADEMARK
Definition atom.h:214
#define ATOM_LIST_VALUE
Definition atom.h:220
#define ATOM_FORMATTING_ITALIC
Definition atom.h:206
#define ATOM_FORMATTING_LINK
Definition atom.h:207
#define ATOM_FORMATTING_SUPERSCRIPT
Definition atom.h:212
#define ATOM_FORMATTING_INDEX
Definition atom.h:205
#define ATOM_FORMATTING_UICONTROL
Definition atom.h:215
#define ATOM_FORMATTING_PARAMETER
Definition atom.h:209
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
AtomType type() const
Return the type of this atom.
Definition atom.h:155
@ TableRight
Definition atom.h:97
@ GeneratedList
Definition atom.h:52
@ BriefRight
Definition atom.h:27
@ TableHeaderRight
Definition atom.h:99
@ FormatElse
Definition atom.h:47
@ InlineImage
Definition atom.h:58
@ TableRowRight
Definition atom.h:101
@ Nop
Definition atom.h:74
@ WarningRight
Definition atom.h:111
@ ListTagRight
Definition atom.h:68
@ NavLink
Definition atom.h:73
@ ListItemNumber
Definition atom.h:66
@ SinceTagRight
Definition atom.h:91
@ CodeBad
Definition atom.h:32
@ AnnotatedList
Definition atom.h:22
@ SectionRight
Definition atom.h:84
@ SectionHeadingLeft
Definition atom.h:85
@ TableLeft
Definition atom.h:96
@ ListItemRight
Definition atom.h:70
@ Image
Definition atom.h:54
@ TableItemRight
Definition atom.h:103
@ ListItemLeft
Definition atom.h:69
@ Code
Definition atom.h:31
@ ListLeft
Definition atom.h:65
@ NavAutoLink
Definition atom.h:72
@ BriefLeft
Definition atom.h:26
@ ImageText
Definition atom.h:55
@ ListRight
Definition atom.h:71
@ ParaRight
Definition atom.h:78
@ Qml
Definition atom.h:79
@ FormattingLeft
Definition atom.h:50
@ FormattingRight
Definition atom.h:51
@ SectionHeadingRight
Definition atom.h:86
@ Link
Definition atom.h:63
@ FormatEndif
Definition atom.h:48
@ SinceTagLeft
Definition atom.h:90
@ AutoLink
Definition atom.h:23
@ TableItemLeft
Definition atom.h:102
@ NoteRight
Definition atom.h:76
@ BaseName
Definition atom.h:24
@ FormatIf
Definition atom.h:49
virtual bool isLinkAtom() const
Definition atom.h:163
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:152
virtual Genus genus()
Definition atom.h:164
Converts Atom chains to QList<IR::ContentBlock> trees.
QList< ContentBlock > build(const Atom *firstAtom)
Walks the atom chain starting at firstAtom and returns a list of ContentBlock trees representing the ...
ContentBuilder(BriefHandling briefHandling=BriefHandling::Skip, int headingOffset=0, DiagnosticHandler diagnosticHandler={})
Constructs a ContentBuilder.
static QString genusToString(Genus genus)
static QString stripCodeMarkerTags(const QString &markedCode)
Definition builder.cpp:14
LinkState
LinkOrigin
BriefHandling
BlockType
static InlineType formattingToInlineType(const QString &formatting)
InlineType
Combined button and popup list for selecting options.
Represents a structural block element in documentation.
Represents inline content within a documentation block.