10using namespace Qt::Literals::StringLiterals;
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
91
92
93
94
95
96
97
98
103 m_inlinePath.clear();
104 m_inlineBaseDepths.clear();
111 processAtoms(firstAtom);
115 if (Q_UNLIKELY(!m_blockPath.isEmpty())) {
116 Q_ASSERT_X(
false,
"ContentBuilder::build",
117 "Unclosed blocks at end of atom chain");
118 while (!m_blockPath.isEmpty())
122 Q_ASSERT(m_inlinePath.isEmpty());
123 Q_ASSERT(m_inlineBaseDepths.isEmpty());
125 Q_ASSERT(!m_inBrief);
131
132
133
134
135
140 atom = skipFormatIfBlock(atom);
147 atom = dispatchAtom(atom);
155
156
157
158
159
160
161
162
163
164
165
166
172 while (atom && depth > 0) {
183
184
185
186
203 openBlock(BlockType::Paragraph);
211 addLeafInline(InlineType::Text, atom->string());
215 addLeafInline(InlineType::Code, atom->string());
223 attrs[
"language"_L1] = u"qml"_s;
225 attrs[
"language"_L1] = u"cpp"_s;
226 attrs[
"bad"_L1] =
true;
227 }
else if (atom->count() >= 2 && !atom->string(1).isEmpty()) {
228 attrs[
"language"_L1] = atom->string(1);
230 attrs[
"language"_L1] = u"cpp"_s;
233 openBlock(BlockType::CodeBlock, attrs);
234 addLeafInline(InlineType::Text, atom->string());
248 link.href = atom->string();
250 addInline(
std::move(link));
256 if (Q_UNLIKELY(m_blockPath.isEmpty()))
263 link.href = atom->string();
265 pushInlineContainer(
std::move(link));
277 const QString &fmt = atom->string();
291 pushInlineContainer(
std::move(bold));
295 InlineType type = formattingToInlineType(fmt);
300 container
.type = type;
301 pushInlineContainer(
std::move(container));
306 const QString &fmt = atom->string();
310 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
311 if (m_inlinePath.size() > base) {
313 m_inlinePath.removeLast();
325 const qsizetype base = m_inlineBaseDepths.isEmpty() ? 0 : m_inlineBaseDepths.last();
326 if (m_inlinePath.size() > base)
327 m_inlinePath.removeLast();
331 case Atom::SectionLeft:
332 openBlock(BlockType::Section);
341 attrs[
"level"_L1] = atom->string().toInt();
342 openBlock(BlockType::SectionHeading, attrs);
352 attrs[
"listType"_L1] = atom->string();
353 openBlock(BlockType::List, attrs);
361 case Atom::ListItemLeft:
362 openBlock(BlockType::ListItem);
374 openBlock(BlockType::Note);
381 case Atom::WarningLeft:
382 openBlock(BlockType::Warning);
390 addLeafInline(InlineType::LineBreak, {});
394 openBlock(BlockType::HorizontalRule);
400 attrs[
"annotatedList"_L1] = atom->string();
401 openBlock(BlockType::Div, attrs);
408 attrs[
"generatedList"_L1] = atom->string();
409 openBlock(BlockType::Div, attrs);
416 const QString &style = atom->string();
417 attrs[
"style"_L1] = style ==
"borderless"_L1 ? style : u"generic"_s;
418 openBlock(BlockType::Table, attrs);
426 case Atom::TableHeaderLeft:
427 openBlock(BlockType::TableHeaderRow);
434 case Atom::TableRowLeft:
435 openBlock(BlockType::TableRow);
444 const QString &spec = atom->string();
445 if (!spec.isEmpty()) {
446 const auto parts = QStringView{spec}.split(u',');
447 if (parts.size() >= 2) {
448 int colspan = qMax(1, parts[0].toInt());
449 int rowspan = qMax(1, parts[1].toInt());
451 attrs[
"colspan"_L1] = colspan;
453 attrs[
"rowspan"_L1] = rowspan;
456 openBlock(BlockType::TableCell, attrs);
464 case Atom::ListTagLeft:
465 openBlock(BlockType::ListItem);
487
488
489
490
491
492
497 block.attributes =
std::move(attrs);
499 m_inlineBaseDepths.append(m_inlinePath.size());
501 if (m_blockPath.isEmpty()) {
502 m_result.append(std::move(block));
503 m_blockPath.append(m_result.size() - 1);
505 auto *parent = resolveBlock();
506 parent->children.append(
std::move(block));
507 m_blockPath.append(parent->children.size() - 1);
512
513
514
515
516
517
518
521 if (!m_blockPath.isEmpty()) {
522 if (Q_UNLIKELY(m_inlineBaseDepths.isEmpty())) {
526 Q_ASSERT_X(
false,
"ContentBuilder::closeBlock",
527 "m_inlineBaseDepths empty with non-empty m_blockPath");
528 m_inlinePath.clear();
530 m_inlineBaseDepths.clear();
534 const qsizetype expectedDepth = m_inlineBaseDepths.last();
535 if (m_inLink && m_inlinePath.size() > expectedDepth)
537 Q_ASSERT(m_inlinePath.size() == expectedDepth);
538 m_inlinePath.resize(expectedDepth);
539 m_inlineBaseDepths.removeLast();
540 m_blockPath.removeLast();
545
546
547
548
549
550
551
552
553
554
557 if (!m_inlinePath.isEmpty()) {
558 resolveInline()->children.append(
std::move(inline_));
559 }
else if (!m_blockPath.isEmpty()) {
560 resolveBlock()->inlineContent.append(
std::move(inline_));
565 Q_ASSERT_X(
false,
"ContentBuilder::addInline",
566 "Inline content without an enclosing block");
571
572
573
579 addInline(
std::move(ic));
583
584
585
586
587
588
589
590
591
594 if (!m_inlinePath.isEmpty()) {
595 auto *parent = resolveInline();
596 parent->children.append(
std::move(container));
597 m_inlinePath.append(parent->children.size() - 1);
598 }
else if (!m_blockPath.isEmpty()) {
599 auto *block = resolveBlock();
600 block->inlineContent.append(
std::move(container));
601 m_inlinePath.append(block->inlineContent.size() - 1);
606
607
608
609
610
611
614 Q_ASSERT(!m_blockPath.isEmpty());
615 Q_ASSERT(m_blockPath[0] >= 0 && m_blockPath[0] < m_result.size());
617 for (qsizetype i = 1; i < m_blockPath.size(); ++i) {
618 Q_ASSERT(m_blockPath[i] >= 0 && m_blockPath[i] < block->children.size());
619 block = &block->children[m_blockPath[i]];
625
626
627
628
629
630
634 Q_ASSERT(!m_inlinePath.isEmpty());
635 Q_ASSERT(m_inlinePath[0] >= 0 && m_inlinePath[0] < block->inlineContent.size());
637 for (qsizetype i = 1; i < m_inlinePath.size(); ++i) {
638 Q_ASSERT(m_inlinePath[i] >= 0 && m_inlinePath[i] < ic->children.size());
639 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.
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 ...
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.