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();
327 link.children.append({
InlineType::Text, atom->string(), {}, {}, {}, {}, {} });
328 addInline(
std::move(link));
334 if (m_blockPath.isEmpty())
335 openBlock(BlockType::Paragraph);
341 link.href = atom->string();
348 auto *mutableAtom =
const_cast<
Atom *>(atom);
350 QString genusStr = genusToString(genus);
351 if (!genusStr.isEmpty())
352 link.attributes[
"linkGenus"_L1] = genusStr;
353 if (Tree *domain = mutableAtom->domain())
354 link.attributes[
"linkModule"_L1] = domain->physicalModuleName();
357 pushInlineContainer(
std::move(link));
369 const QString &fmt = atom->string();
383 pushInlineContainer(
std::move(bold));
387 InlineType type = formattingToInlineType(fmt);
392 container
.type = type;
393 pushInlineContainer(
std::move(container));
398 const QString &fmt = atom->string();
402 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
403 if (m_inlinePath.size() > base) {
405 m_inlinePath.removeLast();
417 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
418 if (m_inlinePath.size() > base)
419 m_inlinePath.removeLast();
423 case Atom::SectionLeft:
424 openBlock(BlockType::Section);
433 attrs[
"level"_L1] = atom->string().toInt() + m_headingOffset;
437 if (atom->count() >= 2)
438 attrs[
"sectionRef"_L1] = atom->string(1);
439 openBlock(BlockType::SectionHeading, attrs);
449 const QString &listType = atom->string();
450 attrs[
"listType"_L1] = listType;
452 openBlock(BlockType::DefinitionList, attrs);
454 openBlock(BlockType::List, attrs);
464 if (parent->type == BlockType::DefinitionList)
465 openBlock(BlockType::DefinitionDescription);
467 openBlock(BlockType::ListItem);
480 openBlock(BlockType::Note);
487 case Atom::WarningLeft:
488 openBlock(BlockType::Warning);
496 addLeafInline(InlineType::LineBreak, {});
500 openBlock(BlockType::HorizontalRule);
506 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedGroup);
507 attrs[
"argument"_L1] = atom->string();
508 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
509 openBlock(BlockType::ListPlaceholder, attrs);
515 const QString arg = atom->string();
517 attrs[
"argument"_L1] = arg;
518 attrs[
"sort"_L1] = placeholderSortAttribute(atom);
520 static constexpr auto classesPrefix =
"classes "_L1;
521 if (arg ==
"annotatedexamples"_L1) {
522 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedExamples);
523 }
else if (arg ==
"annotatedclasses"_L1) {
524 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::AnnotatedClasses);
525 }
else if (arg ==
"classes"_L1 || arg.startsWith(classesPrefix)) {
526 attrs[
"variant"_L1] = toString(ListPlaceholderVariant::CompactClasses);
527 if (arg.startsWith(classesPrefix)) {
528 const QString rootName = arg.sliced(classesPrefix.size()).trimmed();
529 if (!rootName.isEmpty())
530 attrs[
"rootName"_L1] = rootName;
537 QJsonObject fallback;
538 fallback[
"generatedList"_L1] = arg;
539 openBlock(BlockType::Div, fallback);
544 openBlock(BlockType::ListPlaceholder, attrs);
551 QString tableStyle = u"generic"_s;
554 for (
int i = 0; i < atom->count(); ++i) {
555 const QString &arg = atom->string(i);
556 if (arg ==
"borderless"_L1)
558 else if (arg.contains(
'%'_L1))
564 if (width ==
"%"_L1) {
566 int pct = atom->string(0).toInt(&ok);
567 width = ok ? QString::number(pct) +
'%'_L1 : QString();
570 attrs[
"style"_L1] = tableStyle;
571 if (!width.isEmpty())
572 attrs[
"width"_L1] = width;
573 openBlock(BlockType::Table, attrs);
581 case Atom::TableHeaderLeft:
582 openBlock(BlockType::TableHeaderRow);
589 case Atom::TableRowLeft:
590 openBlock(BlockType::TableRow);
599 const QString &spec = atom->string();
600 if (!spec.isEmpty()) {
601 const auto parts = QStringView{spec}.split(u',');
602 if (parts.size() >= 2) {
603 int colspan = qMax(1, parts[0].toInt());
604 int rowspan = qMax(1, parts[1].toInt());
606 attrs[
"colspan"_L1] = colspan;
608 attrs[
"rowspan"_L1] = rowspan;
611 openBlock(BlockType::TableCell, attrs);
619 case Atom::ListTagLeft:
620 openBlock(BlockType::DefinitionTerm);
629 attrs[
"class"_L1] = u"centerAlign"_s;
630 openBlock(BlockType::Paragraph, attrs);
634 img.href = atom->string();
637 addInline(
std::move(img));
647 if (Q_UNLIKELY(m_blockPath.isEmpty()))
652 img.href = atom->string();
655 addInline(
std::move(img));
680
681
682
683
684
685
690 block.attributes =
std::move(attrs);
692 m_inlineBaseDepths.append(m_inlinePath.size());
694 if (m_blockPath.isEmpty()) {
695 m_result.append(std::move(block));
696 m_blockPath.append(m_result.size() - 1);
698 auto *parent = resolveBlock();
699 parent->children.append(
std::move(block));
700 m_blockPath.append(parent->children.size() - 1);
705
706
707
708
709
710
711
714 if (!m_blockPath.isEmpty()) {
715 if (Q_UNLIKELY(m_inlineBaseDepths.isEmpty())) {
716 m_inlinePath.clear();
718 m_inlineBaseDepths.clear();
722 const qsizetype expectedDepth = m_inlineBaseDepths.last();
723 if (m_inLink && m_inlinePath.size() > expectedDepth)
725 m_inlinePath.resize(expectedDepth);
726 m_inlinePath.resize(expectedDepth);
727 m_inlineBaseDepths.removeLast();
728 m_blockPath.removeLast();
733
734
735
736
737
738
739
740
741
742
745 if (!m_inlinePath.isEmpty()) {
746 resolveInline()->children.append(
std::move(inline_));
747 }
else if (!m_blockPath.isEmpty()) {
748 resolveBlock()->inlineContent.append(
std::move(inline_));
751 m_diagnose(QtWarningMsg, u"Dropping inline content outside any block"_s);
756
757
758
764 addInline(
std::move(ic));
768
769
770
771
772
773
774
775
776
779 if (!m_inlinePath.isEmpty()) {
780 auto *parent = resolveInline();
781 parent->children.append(
std::move(container));
782 m_inlinePath.append(parent->children.size() - 1);
783 }
else if (!m_blockPath.isEmpty()) {
784 auto *block = resolveBlock();
785 block->inlineContent.append(
std::move(container));
786 m_inlinePath.append(block->inlineContent.size() - 1);
791
792
793
794
795
796
799 Q_ASSERT(!m_blockPath.isEmpty());
800 Q_ASSERT(m_blockPath[0] >= 0 && m_blockPath[0] < m_result.size());
802 for (qsizetype i = 1; i < m_blockPath.size(); ++i) {
803 Q_ASSERT(m_blockPath[i] >= 0 && m_blockPath[i] < block->children.size());
804 block = &block->children[m_blockPath[i]];
810
811
812
813
814
815
819 Q_ASSERT(!m_inlinePath.isEmpty());
820 Q_ASSERT(m_inlinePath[0] >= 0 && m_inlinePath[0] < block->inlineContent.size());
822 for (qsizetype i = 1; i < m_inlinePath.size(); ++i) {
823 Q_ASSERT(m_inlinePath[i] >= 0 && m_inlinePath[i] < ic->children.size());
824 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.
Represents inline content within a documentation block.