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
129
130
131
132
133
134
135
136
137
138
139
140
141
143 DiagnosticHandler diagnosticHandler)
144 : m_briefHandling(briefHandling), m_headingOffset(headingOffset),
169
170
171
172
173
174
175
176
181 m_inlinePath.clear();
182 m_inlineBaseDepths.clear();
189 processAtoms(firstAtom);
193 while (!m_blockPath.isEmpty())
195 m_inlinePath.clear();
196 m_inlineBaseDepths.clear();
204
205
206
207
208
213 atom = skipFormatIfBlock(atom);
220 atom = dispatchAtom(atom);
228
229
230
231
232
233
234
235
236
237
238
239
245 while (atom && depth > 0) {
256
257
258
259
264 if (m_briefHandling == BriefHandling::Include)
265 openBlock(BlockType::Paragraph);
280 openBlock(BlockType::Paragraph);
288 addLeafInline(InlineType::Text, atom->string());
292 addLeafInline(InlineType::Code, stripCodeMarkerTags(atom->string()));
300 attrs[
"language"_L1] = u"qml"_s;
302 attrs[
"language"_L1] = u"cpp"_s;
303 attrs[
"bad"_L1] =
true;
304 }
else if (atom->count() >= 2 && !atom->string(1).isEmpty()) {
305 attrs[
"language"_L1] = atom->string(1);
307 attrs[
"language"_L1] = u"cpp"_s;
310 openBlock(BlockType::CodeBlock, attrs);
311 addLeafInline(InlineType::Text, stripCodeMarkerTags(atom->string()));
325 link.href = atom->string();
328 const auto *linkAtom =
static_cast<
const LinkAtom *>(atom);
330 linkAtom->location.filePath(),
331 linkAtom->location.lineNo()
334 link.children.append({
InlineType::Text, atom->string(), {}, {}, {}, {}, {} });
335 addInline(
std::move(link));
341 if (m_blockPath.isEmpty())
342 openBlock(BlockType::Paragraph);
348 link.href = atom->string();
355 auto *mutableAtom =
const_cast<
Atom *>(atom);
357 QString genusStr = genusToString(genus);
358 if (!genusStr.isEmpty())
359 link.attributes[
"linkGenus"_L1] = genusStr;
360 if (Tree *domain = mutableAtom->domain())
361 link.attributes[
"linkModule"_L1] = domain->physicalModuleName();
363 const auto *linkAtom =
static_cast<
const LinkAtom *>(mutableAtom);
365 linkAtom->location.filePath(),
366 linkAtom->location.lineNo()
370 pushInlineContainer(
std::move(link));
382 const QString &fmt = atom->string();
396 pushInlineContainer(
std::move(bold));
400 InlineType type = formattingToInlineType(fmt);
405 container
.type = type;
406 pushInlineContainer(
std::move(container));
411 const QString &fmt = atom->string();
415 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
416 if (m_inlinePath.size() > base) {
418 m_inlinePath.removeLast();
430 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
431 if (m_inlinePath.size() > base)
432 m_inlinePath.removeLast();
436 case Atom::SectionLeft:
437 openBlock(BlockType::Section);
446 attrs[
"level"_L1] = atom->string().toInt() + m_headingOffset;
450 if (atom->count() >= 2)
451 attrs[
"sectionRef"_L1] = atom->string(1);
452 openBlock(BlockType::SectionHeading, attrs);
462 const QString &listType = atom->string();
463 attrs[
"listType"_L1] = listType;
465 openBlock(BlockType::DefinitionList, attrs);
467 openBlock(BlockType::List, attrs);
477 if (parent->type == BlockType::DefinitionList)
478 openBlock(BlockType::DefinitionDescription);
480 openBlock(BlockType::ListItem);
493 openBlock(BlockType::Note);
500 case Atom::WarningLeft:
501 openBlock(BlockType::Warning);
509 addLeafInline(InlineType::LineBreak, {});
513 openBlock(BlockType::HorizontalRule);
519 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedGroup);
520 attrs[
"argument"_L1] = atom->string();
521 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
522 openBlock(BlockType::ListPlaceholder, attrs);
528 const QString arg = atom->string();
530 attrs[
"argument"_L1] = arg;
531 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
533 static constexpr auto classesPrefix =
"classes "_L1;
534 if (arg ==
"annotatedexamples"_L1) {
535 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedExamples);
536 }
else if (arg ==
"annotatedclasses"_L1) {
537 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedClasses);
538 }
else if (arg ==
"classes"_L1 || arg.startsWith(classesPrefix)) {
539 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::CompactClasses);
540 if (arg.startsWith(classesPrefix)) {
541 const QString rootName = arg.sliced(classesPrefix.size()).trimmed();
542 if (!rootName.isEmpty())
543 attrs[
"rootName"_L1] = rootName;
550 QJsonObject fallback;
551 fallback[
"generatedList"_L1] = arg;
552 openBlock(BlockType::Div, fallback);
557 openBlock(BlockType::ListPlaceholder, attrs);
564 QString tableStyle = u"generic"_s;
567 for (
int i = 0; i < atom->count(); ++i) {
568 const QString &arg = atom->string(i);
569 if (arg ==
"borderless"_L1)
571 else if (arg.contains(
'%'_L1))
577 if (width ==
"%"_L1) {
579 int pct = atom->string(0).toInt(&ok);
580 width = ok ? QString::number(pct) +
'%'_L1 : QString();
583 attrs[
"style"_L1] = tableStyle;
584 if (!width.isEmpty())
585 attrs[
"width"_L1] = width;
586 openBlock(BlockType::Table, attrs);
594 case Atom::TableHeaderLeft:
595 openBlock(BlockType::TableHeaderRow);
602 case Atom::TableRowLeft:
603 openBlock(BlockType::TableRow);
612 const QString &spec = atom->string();
613 if (!spec.isEmpty()) {
614 const auto parts = QStringView{spec}.split(u',');
615 if (parts.size() >= 2) {
616 int colspan = qMax(1, parts[0].toInt());
617 int rowspan = qMax(1, parts[1].toInt());
619 attrs[
"colspan"_L1] = colspan;
621 attrs[
"rowspan"_L1] = rowspan;
624 openBlock(BlockType::TableCell, attrs);
632 case Atom::ListTagLeft:
633 openBlock(BlockType::DefinitionTerm);
642 attrs[
"class"_L1] = u"centerAlign"_s;
643 openBlock(BlockType::Paragraph, attrs);
647 img.href = atom->string();
650 addInline(
std::move(img));
660 if (Q_UNLIKELY(m_blockPath.isEmpty()))
665 img.href = atom->string();
668 addInline(
std::move(img));
693
694
695
696
697
698
703 block.attributes =
std::move(attrs);
705 m_inlineBaseDepths.append(m_inlinePath.size());
707 if (m_blockPath.isEmpty()) {
708 m_result.append(std::move(block));
709 m_blockPath.append(m_result.size() - 1);
711 auto *parent = resolveBlock();
712 parent->children.append(
std::move(block));
713 m_blockPath.append(parent->children.size() - 1);
718
719
720
721
722
723
724
727 if (!m_blockPath.isEmpty()) {
728 if (Q_UNLIKELY(m_inlineBaseDepths.isEmpty())) {
729 m_inlinePath.clear();
731 m_inlineBaseDepths.clear();
735 const qsizetype expectedDepth = m_inlineBaseDepths.last();
736 if (m_inLink && m_inlinePath.size() > expectedDepth)
738 m_inlinePath.resize(expectedDepth);
739 m_inlinePath.resize(expectedDepth);
740 m_inlineBaseDepths.removeLast();
741 m_blockPath.removeLast();
746
747
748
749
750
751
752
753
754
755
758 if (!m_inlinePath.isEmpty()) {
759 resolveInline()->children.append(
std::move(inline_));
760 }
else if (!m_blockPath.isEmpty()) {
761 resolveBlock()->inlineContent.append(
std::move(inline_));
764 m_diagnose(QtWarningMsg, u"Dropping inline content outside any block"_s);
769
770
771
777 addInline(
std::move(ic));
781
782
783
784
785
786
787
788
789
792 if (!m_inlinePath.isEmpty()) {
793 auto *parent = resolveInline();
794 parent->children.append(
std::move(container));
795 m_inlinePath.append(parent->children.size() - 1);
796 }
else if (!m_blockPath.isEmpty()) {
797 auto *block = resolveBlock();
798 block->inlineContent.append(
std::move(container));
799 m_inlinePath.append(block->inlineContent.size() - 1);
804
805
806
807
808
809
812 Q_ASSERT(!m_blockPath.isEmpty());
813 Q_ASSERT(m_blockPath[0] >= 0 && m_blockPath[0] < m_result.size());
815 for (qsizetype i = 1; i < m_blockPath.size(); ++i) {
816 Q_ASSERT(m_blockPath[i] >= 0 && m_blockPath[i] < block->children.size());
817 block = &block->children[m_blockPath[i]];
823
824
825
826
827
828
832 Q_ASSERT(!m_inlinePath.isEmpty());
833 Q_ASSERT(m_inlinePath[0] >= 0 && m_inlinePath[0] < block->inlineContent.size());
835 for (qsizetype i = 1; i < m_inlinePath.size(); ++i) {
836 Q_ASSERT(m_inlinePath[i] >= 0 && m_inlinePath[i] < ic->children.size());
837 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.