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