14using namespace Qt::Literals::StringLiterals;
18 static const QRegularExpression tag(u"</?@[^>]*>"_s);
19 QString t = markedCode;
20 t.replace(tag, QString());
21 t.replace(u"""_s, u"\""_s);
22 t.replace(u">"_s, u">"_s);
23 t.replace(u"<"_s, u"<"_s);
24 t.replace(u"&"_s, u"&"_s);
31 case Genus::CPP:
return u"cpp"_s;
32 case Genus::QML:
return u"qml"_s;
33 case Genus::DOC:
return u"doc"_s;
34 case Genus::API:
return u"api"_s;
35 case Genus::DontCare:
return {};
47 const QStringList &args = atom->strings();
48 const QString directive = args.size() > 1 ? args.at(1) : QString();
49 return Sorting::parseSortOrder(directive) == Qt::DescendingOrder
50 ? u"descending"_s : u"ascending"_s;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
133
134
135
136
137
138
139
140
141
142
143
144
145
147 DiagnosticHandler diagnosticHandler)
148 : m_briefHandling(briefHandling), m_headingOffset(headingOffset),
173
174
175
176
177
178
179
180
185 m_inlinePath.clear();
186 m_inlineBaseDepths.clear();
193 processAtoms(firstAtom);
197 while (!m_blockPath.isEmpty())
199 m_inlinePath.clear();
200 m_inlineBaseDepths.clear();
208
209
210
211
212
217 atom = skipFormatIfBlock(atom);
224 atom = dispatchAtom(atom);
232
233
234
235
236
237
238
239
240
241
242
243
249 while (atom && depth > 0) {
260
261
262
263
268 if (m_briefHandling == BriefHandling::Include)
269 openBlock(BlockType::Paragraph);
284 openBlock(BlockType::Paragraph);
292 addLeafInline(InlineType::Text, atom->string());
296 addLeafInline(InlineType::Code, stripCodeMarkerTags(atom->string()));
304 attrs[
"language"_L1] = u"qml"_s;
306 attrs[
"language"_L1] = u"text"_s;
307 attrs[
"bad"_L1] =
true;
308 }
else if (atom->count() >= 2 && !atom->string(1).isEmpty()) {
309 attrs[
"language"_L1] = atom->string(1);
311 attrs[
"language"_L1] = u"cpp"_s;
314 openBlock(BlockType::CodeBlock, attrs);
315 addLeafInline(InlineType::Text, stripCodeMarkerTags(atom->string()));
329 link.href = atom->string();
332 const auto *linkAtom =
static_cast<
const LinkAtom *>(atom);
334 linkAtom->location.filePath(),
335 linkAtom->location.lineNo()
338 link.children.append({
InlineType::Text, atom->string(), {}, {}, {}, {}, {} });
339 addInline(
std::move(link));
345 if (m_blockPath.isEmpty())
346 openBlock(BlockType::Paragraph);
352 link.href = atom->string();
359 auto *mutableAtom =
const_cast<
Atom *>(atom);
361 QString genusStr = genusToString(genus);
362 if (!genusStr.isEmpty())
363 link.attributes[
"linkGenus"_L1] = genusStr;
364 if (Tree *domain = mutableAtom->domain())
365 link.attributes[
"linkModule"_L1] = domain->physicalModuleName();
367 const auto *linkAtom =
static_cast<
const LinkAtom *>(mutableAtom);
369 linkAtom->location.filePath(),
370 linkAtom->location.lineNo()
374 pushInlineContainer(
std::move(link));
386 const QString &fmt = atom->string();
400 pushInlineContainer(
std::move(bold));
404 InlineType type = formattingToInlineType(fmt);
409 container
.type = type;
410 pushInlineContainer(
std::move(container));
415 const QString &fmt = atom->string();
419 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
420 if (m_inlinePath.size() > base) {
422 m_inlinePath.removeLast();
434 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
435 if (m_inlinePath.size() > base)
436 m_inlinePath.removeLast();
440 case Atom::SectionLeft:
441 openBlock(BlockType::Section);
450 attrs[
"level"_L1] = atom->string().toInt() + m_headingOffset;
454 if (atom->count() >= 2)
455 attrs[
"sectionRef"_L1] = atom->string(1);
456 openBlock(BlockType::SectionHeading, attrs);
466 const QString &listType = atom->string();
467 attrs[
"listType"_L1] = listType;
469 openBlock(BlockType::DefinitionList, attrs);
471 openBlock(BlockType::List, attrs);
481 if (parent->type == BlockType::DefinitionList)
482 openBlock(BlockType::DefinitionDescription);
484 openBlock(BlockType::ListItem);
497 openBlock(BlockType::Note);
504 case Atom::WarningLeft:
505 openBlock(BlockType::Warning);
512 case Atom::ImportantLeft:
513 openBlock(BlockType::Important);
521 addLeafInline(InlineType::LineBreak, {});
525 openBlock(BlockType::HorizontalRule);
531 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedGroup);
532 attrs[
"argument"_L1] = atom->string();
533 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
534 openBlock(BlockType::ListPlaceholder, attrs);
540 const QString arg = atom->string();
542 attrs[
"argument"_L1] = arg;
543 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
545 static constexpr auto classesPrefix =
"classes "_L1;
546 if (arg ==
"annotatedexamples"_L1) {
547 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedExamples);
548 }
else if (arg ==
"annotatedclasses"_L1) {
549 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedClasses);
550 }
else if (arg ==
"classes"_L1 || arg.startsWith(classesPrefix)) {
551 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::CompactClasses);
552 if (arg.startsWith(classesPrefix)) {
553 const QString rootName = arg.sliced(classesPrefix.size()).trimmed();
554 if (!rootName.isEmpty())
555 attrs[
"rootName"_L1] = rootName;
562 QJsonObject fallback;
563 fallback[
"generatedList"_L1] = arg;
564 openBlock(BlockType::Div, fallback);
569 openBlock(BlockType::ListPlaceholder, attrs);
576 QString tableStyle = u"generic"_s;
579 for (
int i = 0; i < atom->count(); ++i) {
580 const QString &arg = atom->string(i);
581 if (arg ==
"borderless"_L1)
583 else if (arg.contains(
'%'_L1))
589 if (width ==
"%"_L1) {
591 int pct = atom->string(0).toInt(&ok);
592 width = ok ? QString::number(pct) +
'%'_L1 : QString();
595 attrs[
"style"_L1] = tableStyle;
596 if (!width.isEmpty())
597 attrs[
"width"_L1] = width;
598 openBlock(BlockType::Table, attrs);
606 case Atom::TableHeaderLeft:
607 openBlock(BlockType::TableHeaderRow);
614 case Atom::TableRowLeft:
615 openBlock(BlockType::TableRow);
624 const QString &spec = atom->string();
625 if (!spec.isEmpty()) {
626 const auto parts = QStringView{spec}.split(u',');
627 if (parts.size() >= 2) {
628 int colspan = qMax(1, parts[0].toInt());
629 int rowspan = qMax(1, parts[1].toInt());
631 attrs[
"colspan"_L1] = colspan;
633 attrs[
"rowspan"_L1] = rowspan;
636 openBlock(BlockType::TableCell, attrs);
644 case Atom::ListTagLeft:
645 openBlock(BlockType::DefinitionTerm);
654 attrs[
"class"_L1] = u"centerAlign"_s;
655 openBlock(BlockType::Paragraph, attrs);
659 img.href = atom->string();
662 addInline(
std::move(img));
672 if (Q_UNLIKELY(m_blockPath.isEmpty()))
677 img.href = atom->string();
680 addInline(
std::move(img));
692 attrs[
"class"_L1] = u"figCaption"_s;
693 openBlock(BlockType::Paragraph, attrs);
716
717
718
719
720
721
726 block.attributes =
std::move(attrs);
728 m_inlineBaseDepths.append(m_inlinePath.size());
730 if (m_blockPath.isEmpty()) {
731 m_result.append(std::move(block));
732 m_blockPath.append(m_result.size() - 1);
734 auto *parent = resolveBlock();
735 parent->children.append(
std::move(block));
736 m_blockPath.append(parent->children.size() - 1);
741
742
743
744
745
746
747
750 if (!m_blockPath.isEmpty()) {
751 if (Q_UNLIKELY(m_inlineBaseDepths.isEmpty())) {
752 m_inlinePath.clear();
754 m_inlineBaseDepths.clear();
758 const qsizetype expectedDepth = m_inlineBaseDepths.last();
759 if (m_inLink && m_inlinePath.size() > expectedDepth)
761 m_inlinePath.resize(expectedDepth);
762 m_inlinePath.resize(expectedDepth);
763 m_inlineBaseDepths.removeLast();
764 m_blockPath.removeLast();
769
770
771
772
773
774
775
776
777
778
781 if (!m_inlinePath.isEmpty()) {
782 resolveInline()->children.append(
std::move(inline_));
783 }
else if (!m_blockPath.isEmpty()) {
784 resolveBlock()->inlineContent.append(
std::move(inline_));
787 m_diagnose(QtWarningMsg, u"Dropping inline content outside any block"_s);
792
793
794
800 addInline(
std::move(ic));
804
805
806
807
808
809
810
811
812
815 if (!m_inlinePath.isEmpty()) {
816 auto *parent = resolveInline();
817 parent->children.append(
std::move(container));
818 m_inlinePath.append(parent->children.size() - 1);
819 }
else if (!m_blockPath.isEmpty()) {
820 auto *block = resolveBlock();
821 block->inlineContent.append(
std::move(container));
822 m_inlinePath.append(block->inlineContent.size() - 1);
827
828
829
830
831
832
835 Q_ASSERT(!m_blockPath.isEmpty());
836 Q_ASSERT(m_blockPath[0] >= 0 && m_blockPath[0] < m_result.size());
838 for (qsizetype i = 1; i < m_blockPath.size(); ++i) {
839 Q_ASSERT(m_blockPath[i] >= 0 && m_blockPath[i] < block->children.size());
840 block = &block->children[m_blockPath[i]];
846
847
848
849
850
851
855 Q_ASSERT(!m_inlinePath.isEmpty());
856 Q_ASSERT(m_inlinePath[0] >= 0 && m_inlinePath[0] < block->inlineContent.size());
858 for (qsizetype i = 1; i < m_inlinePath.size(); ++i) {
859 Q_ASSERT(m_inlinePath[i] >= 0 && m_inlinePath[i] < ic->children.size());
860 ic = &ic->children[m_inlinePath[i]];
#define ATOM_FORMATTING_TELETYPE
#define ATOM_FORMATTING_UNDERLINE
#define ATOM_FORMATTING_NOTRANSLATE
#define ATOM_FORMATTING_SUBSCRIPT
#define ATOM_FORMATTING_BOLD
#define ATOM_FORMATTING_TRADEMARK
#define ATOM_FORMATTING_ITALIC
#define ATOM_FORMATTING_LINK
#define ATOM_FORMATTING_SUPERSCRIPT
#define ATOM_FORMATTING_INDEX
#define ATOM_FORMATTING_UICONTROL
#define ATOM_FORMATTING_PARAMETER
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
virtual bool isLinkAtom() const
const Atom * next() const
Return the next atom in the atom list.
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)
static QString placeholderSortAttribute(const Atom *atom)
static InlineType formattingToInlineType(const QString &formatting)
Combined button and popup list for selecting options.
Represents a structural block element in documentation.
LinkData(LinkOrigin o, LinkState s, std::optional< SourceLocation > loc=std::nullopt)
Represents inline content within a documentation block.