36#include <unordered_map>
57#if !ENABLE_MARKDOWN_TRACING
61#define AUTO_TRACE(...) (void)0
62#define AUTO_TRACE_ADD(...) (void)0
63#define AUTO_TRACE_EXIT(...) (void)0
78 ((c>='a' && c<='z') || \
79 (c>='A' && c<='Z') || \
80 (c>='0' && c<='9') || \
81 (static_cast<unsigned char>(c)>=0x80))
85 (c=='-' || c=='+' || c=='!' || \
86 c=='?' || c=='$' || c=='@' || \
87 c=='&' || c=='*' || c=='_' || c=='%' || \
88 c=='[' || c=='(' || c=='.' || \
89 c=='>' || c==':' || c==',' || \
90 c==';' || c=='\'' || c=='"' || c=='`')
92// is character at position i in data allowed before an emphasis section
93#define isOpenEmphChar(c) \
94 (c=='\n' || c==' ' || c=='\'' || c=='<' || \
95 c=='>' || c=='{' || c=='(' || c=='[' || \
96 c==',' || c==':' || c==';')
98// is character at position i in data an escape that prevents ending an emphasis section
99// so for example *bla (*.txt) is cool*
100#define ignoreCloseEmphChar(c,cn) \
101 (c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || \
108 TableCell() : colSpan(false) {}
113struct Markdown::Private
115 Private(const QCString &fn,int line,int indent)
116 : fileName(fn), lineNr(line), indentLevel(indent)
118 // setup callback table for special characters
119 actions[static_cast<unsigned int>('_')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
120 actions[static_cast<unsigned int>('*')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
121 actions[static_cast<unsigned int>('~')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
122 actions[static_cast<unsigned int>('`')] = [this](std::string_view data,size_t offset) { return processCodeSpan (data,offset); };
123 actions[static_cast<unsigned int>('\\')]= [this](std::string_view data,size_t offset) { return processSpecialCommand(data,offset); };
124 actions[static_cast<unsigned int>('@')] = [this](std::string_view data,size_t offset) { return processSpecialCommand(data,offset); };
125 actions[static_cast<unsigned int>('[')] = [this](std::string_view data,size_t offset) { return processLink (data,offset); };
126 actions[static_cast<unsigned int>('!')] = [this](std::string_view data,size_t offset) { return processLink (data,offset); };
127 actions[static_cast<unsigned int>('<')] = [this](std::string_view data,size_t offset) { return processHtmlTag (data,offset); };
128 actions[static_cast<unsigned int>('-')] = [this](std::string_view data,size_t offset) { return processNmdash (data,offset); };
129 actions[static_cast<unsigned int>('"')] = [this](std::string_view data,size_t offset) { return processQuoted (data,offset); };
132 QCString processQuotations(std::string_view
data,
size_t refIndent);
133 QCString processBlocks(std::string_view
data,
size_t indent);
134 QCString isBlockCommand(std::string_view
data,
size_t offset);
135 size_t isSpecialCommand(std::string_view
data,
size_t offset);
136 size_t findEndOfLine(std::string_view
data,
size_t offset);
137 int processHtmlTagWrite(std::string_view
data,
size_t offset,
bool doWrite);
138 int processHtmlTag(std::string_view
data,
size_t offset);
139 int processEmphasis(std::string_view
data,
size_t offset);
140 int processEmphasis1(std::string_view
data,
char c);
141 int processEmphasis2(std::string_view
data,
char c);
142 int processEmphasis3(std::string_view
data,
char c);
143 int processNmdash(std::string_view
data,
size_t offset);
144 int processQuoted(std::string_view
data,
size_t offset);
145 int processCodeSpan(std::string_view
data,
size_t offset);
146 int processSpecialCommand(std::string_view
data,
size_t offset);
147 int processLink(std::string_view
data,
size_t offset);
148 size_t findEmphasisChar(std::string_view,
char c,
size_t c_size);
149 void addStrEscapeUtf8Nbsp(std::string_view
data);
150 void processInline(std::string_view
data);
151 void writeMarkdownImage(std::string_view
fmt,
bool inline_img,
bool explicitTitle,
155 int isHeaderline(std::string_view
data,
bool allowAdjustLevel);
157 bool *pIsIdGenerated=
nullptr);
158 void writeOneLineHeaderOrRuler(std::string_view
data);
159 void writeFencedCodeBlock(std::string_view
data, std::string_view lang,
160 size_t blockStart,
size_t blockEnd);
161 size_t writeBlockQuote(std::string_view
data);
162 size_t writeCodeBlock(std::string_view,
size_t refIndent);
163 size_t writeTableBlock(std::string_view
data);
164 QCString extractTitleId(
QCString &title,
int level,
bool *pIsIdGenerated=
nullptr);
172 using Action_t = std::function<int(std::string_view,
size_t)>;
183 :
prv(std::make_unique<
Private>(fileName,lineNr,indentLevel))
185 using namespace std::placeholders;
210 if (
data[0] ==
'\n')
return 1;
214 return (
data.size()>8 &&
data[8]==
' ') ? 9 : 8;
223 if (
s.isEmpty())
return s;
225 const char *p=
s.data();
229 if (c==
'"' && pc!=
'\\') result+=
'\\';
241 if (
s.isEmpty())
return s;
242 bool insideQuote=
FALSE;
244 const char *p=
s.data();
251 if (pc!=
'\\') { insideQuote=!insideQuote; }
261 if ((p[0]==
':') && (p[1]==
':'))
273 case '\\':
if (!insideQuote) { result+=
'\\'; } result+=
'\\';
break;
274 case '@':
if (!insideQuote) { result+=
'\\'; } result+=
'@';
break;
277 case '#':
if (!insideQuote) { result+=
'\\'; } result+=
'#';
break;
278 case '$':
if (!insideQuote) { result+=
'\\'; } result+=
'$';
break;
279 case '&':
if (!insideQuote) { result+=
'\\'; } result+=
'&';
break;
294 if (leftMarker && rightMarker)
302 else if (rightMarker)
317 for (
const auto &attr_ : attrList)
320 int i = attr.
find(
':');
327 return attr.
mid(
i+1);
364 using EndBlockFunc =
QCString (*)(
const std::string &,bool,char);
366 static const auto getEndBlock = [](
const std::string &blockName,bool,char) ->
QCString
368 return "end"+blockName;
370 static const auto getEndCode = [](
const std::string &blockName,
bool openBracket,char) ->
QCString
372 return openBracket ?
QCString(
"}") :
"end"+blockName;
374 static const auto getEndUml = [](
const std::string &,bool,char) ->
QCString
378 static const auto getEndFormula = [](
const std::string &,bool,
char nextChar) ->
QCString
382 case '$':
return "f$";
383 case '(':
return "f)";
384 case '[':
return "f]";
385 case '{':
return "f}";
391 static const std::unordered_map<std::string,EndBlockFunc> blockNames =
393 {
"dot", getEndBlock },
394 {
"code", getEndCode },
395 {
"icode", getEndBlock },
396 {
"msc", getEndBlock },
397 {
"verbatim", getEndBlock },
398 {
"iverbatim", getEndBlock },
399 {
"iliteral", getEndBlock },
400 {
"latexonly", getEndBlock },
401 {
"htmlonly", getEndBlock },
402 {
"xmlonly", getEndBlock },
403 {
"rtfonly", getEndBlock },
404 {
"manonly", getEndBlock },
405 {
"docbookonly", getEndBlock },
406 {
"startuml", getEndUml },
407 {
"f", getEndFormula }
411 bool openBracket = offset>0 &&
data.data()[-1]==
'{';
412 bool isEscaped = offset>0 && (
data.data()[-1]==
'\\' ||
data.data()[-1]==
'@');
418 std::string blockName(
data.substr(1,
end-1));
419 auto it = blockNames.find(blockName);
421 if (it!=blockNames.end())
423 result = it->second(blockName, openBracket,
end<
size ?
data[
end] : 0);
433 using EndCmdFunc = size_t (*)(std::string_view,size_t);
435 static const auto endOfLine = [](std::string_view data_,
size_t offset_) ->
size_t
440 while (offset_<data_.size() && ((c=data_[offset_])!=
'\n' || lc==
'\\'))
442 if (c==
'\\') lc=
'\\';
443 else if (c!=
' ') lc=0;
449 static const auto endOfLabels = [](std::string_view data_,
size_t offset_,
bool multi_) ->
size_t
451 if (offset_<data_.size() && data_[offset_]==
' ')
459 while (offset_<data_.size() && data_[offset_]==
' ')
464 while (offset_<data_.size() && (c=data_[offset_])!=
' ' && c!=
',' && c!=
'\\' && c!=
'@' && c!=
'\n')
469 if (multi_ && offset_<data_.size() && (data_[offset_]==
',' || data_[offset_]==
' '))
471 size_t off = offset_;
472 while (off<data_.size() && data_[off]==
' ')
476 if (off<data_.size() && data_[off]==
',')
495 static const auto endOfLabel = [](std::string_view data_,
size_t offset_) ->
size_t
497 return endOfLabels(data_,offset_,
false);
500 static const auto endOfLabelOpt = [](std::string_view data_,
size_t offset_) ->
size_t
502 size_t index=offset_;
503 if (index<data_.size() && data_[index]==
' ')
506 while (index<data_.size() && data_[index]==
' ') index++;
508 if (index<data_.size() && data_[index]==
'{')
512 while (index<data_.size() && (c=data_[index])!=
'}' && c!=
'\\' && c!=
'@' && c!=
'\n') index++;
513 if (index==data_.size() || data_[index]!=
'}')
return 0;
516 return endOfLabel(data_,offset_);
519 static const auto endOfParam = [](std::string_view data_,
size_t offset_) ->
size_t
521 size_t index=offset_;
522 if (index<data_.size() && data_[index]==
' ')
525 while (index<data_.size() && data_[index]==
' ') index++;
527 if (index<data_.size() && data_[index]==
'[')
531 while (index<data_.size() && (c=data_[index])!=
']' && c!=
'\n') index++;
532 if (index==data_.size() || data_[index]!=
']')
return 0;
535 return endOfLabels(data_,offset_,
true);
538 static const auto endOfRetVal = [](std::string_view data_,
size_t offset_) ->
size_t
540 return endOfLabels(data_,offset_,
true);
543 static const auto endOfFuncLike = [](std::string_view data_,
size_t offset_,
bool allowSpaces) ->
size_t
545 if (offset_<data_.size() && data_[offset_]==
' ')
550 while (offset_<data_.size() && data_[offset_]==
' ')
555 while (offset_<data_.size() && (c=data_[offset_])!=
'\n' && (allowSpaces || c!=
' ') && c!=
'(')
557 if (
literal_at(data_.substr(offset_),
"\\ilinebr "))
break;
564 while (offset_<data_.size() && (c=data_[offset_++]))
567 else if (c==
')') count--;
568 if (count==0)
return offset_;
576 static const auto endOfFunc = [](std::string_view data_,
size_t offset_) ->
size_t
578 return endOfFuncLike(data_,offset_,
true);
581 static const auto endOfGuard = [](std::string_view data_,
size_t offset_) ->
size_t
583 return endOfFuncLike(data_,offset_,
false);
586 static const std::unordered_map<std::string,EndCmdFunc> cmdNames =
589 {
"addindex", endOfLine },
590 {
"addtogroup", endOfLabel },
591 {
"anchor", endOfLabel },
594 {
"category", endOfLine },
595 {
"cite", endOfLabel },
596 {
"class", endOfLine },
597 {
"concept", endOfLine },
598 {
"copybrief", endOfFunc },
599 {
"copydetails", endOfFunc },
600 {
"copydoc", endOfFunc },
601 {
"def", endOfFunc },
602 {
"defgroup", endOfLabel },
603 {
"diafile", endOfLine },
604 {
"dir", endOfLine },
605 {
"dockbookinclude",endOfLine },
606 {
"dontinclude", endOfLine },
607 {
"dotfile", endOfLine },
609 {
"elseif", endOfGuard },
610 {
"em", endOfLabel },
611 {
"emoji", endOfLabel },
612 {
"enum", endOfLabel },
613 {
"example", endOfLine },
614 {
"exception", endOfLine },
615 {
"extends", endOfLabel },
616 {
"file", endOfLine },
618 {
"headerfile", endOfLine },
619 {
"htmlinclude", endOfLine },
620 {
"ianchor", endOfLabelOpt },
621 {
"idlexcept", endOfLine },
622 {
"if", endOfGuard },
623 {
"ifnot", endOfGuard },
624 {
"image", endOfLine },
625 {
"implements", endOfLine },
626 {
"include", endOfLine },
627 {
"includedoc", endOfLine },
628 {
"includelineno", endOfLine },
629 {
"ingroup", endOfLabel },
630 {
"interface", endOfLine },
631 {
"latexinclude", endOfLine },
632 {
"maninclude", endOfLine },
633 {
"memberof", endOfLabel },
634 {
"mscfile", endOfLine },
635 {
"namespace", endOfLabel },
636 {
"noop", endOfLine },
637 {
"overload", endOfLine },
639 {
"package", endOfLabel },
640 {
"page", endOfLabel },
641 {
"paragraph", endOfLabel },
642 {
"param", endOfParam },
643 {
"property", endOfLine },
644 {
"protocol", endOfLine },
645 {
"qualifier", endOfLine },
646 {
"ref", endOfLabel },
647 {
"refitem", endOfLine },
648 {
"related", endOfLabel },
649 {
"relatedalso", endOfLabel },
650 {
"relates", endOfLabel },
651 {
"relatesalso", endOfLabel },
652 {
"retval", endOfRetVal},
653 {
"rtfinclude", endOfLine },
654 {
"section", endOfLabel },
655 {
"skip", endOfLine },
656 {
"skipline", endOfLine },
657 {
"snippet", endOfLine },
658 {
"snippetdoc", endOfLine },
659 {
"snippetlineno", endOfLine },
660 {
"struct", endOfLine },
661 {
"subpage", endOfLabel },
662 {
"subparagraph", endOfLabel },
663 {
"subsubparagraph",endOfLabel },
664 {
"subsection", endOfLabel },
665 {
"subsubsection", endOfLabel },
666 {
"throw", endOfLabel },
667 {
"throws", endOfLabel },
668 {
"tparam", endOfLabel },
669 {
"typedef", endOfLine },
670 {
"plantumlfile", endOfLine },
671 {
"union", endOfLine },
672 {
"until", endOfLine },
673 {
"var", endOfLine },
674 {
"verbinclude", endOfLine },
675 {
"weakgroup", endOfLabel },
676 {
"xmlinclude", endOfLine },
677 {
"xrefitem", endOfLabel }
680 bool isEscaped = offset>0 && (
data.data()[-1]==
'\\' ||
data.data()[-1]==
'@');
681 if (isEscaped)
return 0;
686 if (
end==1)
return 0;
687 std::string cmdName(
data.substr(1,
end-1));
689 auto it = cmdNames.find(cmdName);
690 if (it!=cmdNames.end())
745 return static_cast<int>(
i);
757 while (
i<
size && enb<snb)
759 if (
data[
i]==
'`') enb++;
760 if (snb==1 &&
data[
i]==
'\'')
break;
770 size_t l = endBlockName.
length();
797 else if (
data[
i]==
'\n')
827 if (len==0) {
return 0; }
829 if (
i>=
size) {
return 0; }
842 return static_cast<int>(
i+1);
865 if (c ==
'~')
out+=
"<strike>";
866 else out+=
"<strong>";
868 if (c ==
'~')
out+=
"</strike>";
869 else out+=
"</strong>";
871 return static_cast<int>(
i+2);
906 out+=
"</strong></em>";
908 return static_cast<int>(
i+3);
921 return static_cast<int>(len - 2);
935 return static_cast<int>(len - 1);
964 if (count==2 &&
size > 2 &&
data[2]==
'>')
966 if (count==3 &&
size > 3 &&
data[3]==
'>')
968 if (count==2 && (offset<8 || !
literal_at(
data.data()-8,
"operator")))
993 if (
data[
i]==
'\n') nl++;
1000 return static_cast<int>(
i+1);
1012 if (offset>0 &&
data.data()[-1]==
'\\') {
return 0; }
1022 if (tagName.
lower()==
"pre")
1024 bool insideStr=
FALSE;
1028 if (!insideStr && c==
'<')
1030 if (
data[
i+1]==
'/' &&
1031 tolower(
data[
i+2])==
'p' && tolower(
data[
i+3])==
'r' &&
1032 tolower(
data[
i+4])==
'e' && tolower(
data[
i+5])==
'>')
1034 if (doWrite)
out+=
data.substr(0,
i+6);
1037 return static_cast<int>(
i+6);
1040 else if (insideStr && c==
'"')
1058 if (doWrite)
out+=
data.substr(0,
i+2);
1060 return static_cast<int>(
i+2);
1062 else if (
data[
i]==
'>')
1065 if (doWrite)
out+=
data.substr(0,
i+1);
1067 return static_cast<int>(
i+1);
1069 else if (
data[
i]==
' ')
1072 bool insideAttr=
FALSE;
1075 if (!insideAttr &&
data[
i]==
'"')
1083 else if (!insideAttr &&
data[
i]==
'>')
1086 if (doWrite)
out+=
data.substr(0,
i+1);
1088 return static_cast<int>(
i+1);
1120 if (
size>2 && c!=
'~' &&
data[1]!=c)
1123 if (
data[1]==
' ' ||
data[1]==
'\n' ||
1133 if (
data[2]==
' ' ||
data[2]==
'\n' ||
1143 if (
data[3]==
' ' ||
data[3]==
'\n' ||
1155 std::string_view
fmt,
bool inline_img,
bool explicitTitle,
1160 AUTO_TRACE(
"fmt={} inline_img={} explicitTitle={} title={} content={} link={} attrs={}",
1171 out+=link.
mid(fd ? 0 : 5);
1172 if (!explicitTitle && !content.
isEmpty())
1178 else if ((content.
isEmpty() || explicitTitle) && !title.
isEmpty())
1204 bool isImageLink =
FALSE;
1205 bool isImageInline =
FALSE;
1220 while (pos>=-
static_cast<int>(offset) && numNLsNeeded>0)
1222 if (
data.data()[pos]==
'\n') numNLsNeeded--;
1223 else if (
data.data()[pos]!=
' ')
1233 size_t contentStart=
i;
1240 if (
data[
i-1]==
'\\')
1243 else if (
data[
i]==
'[')
1247 else if (
data[
i]==
']')
1250 if (level<=0)
break;
1252 else if (
data[
i]==
'\n')
1255 if (nl>1) {
return 0; }
1261 if (
i>=
size)
return 0;
1262 size_t contentEnd=
i;
1263 content =
data.substr(contentStart,contentEnd-contentStart);
1265 if (!isImageLink && content.
isEmpty()) {
return 0; }
1268 bool whiteSpace =
false;
1270 while (
i<
size &&
data[
i]==
' ') { whiteSpace =
true;
i++; }
1280 bool explicitTitle=
FALSE;
1285 bool uriFormat=
false;
1286 if (
i<
size &&
data[
i]==
'<') {
i++; uriFormat=
true; }
1294 if (nl>1) {
return 0; }
1296 else if (
data[
i]==
'(')
1300 else if (
data[
i]==
')')
1312 link =
data.substr(linkStart,
i-linkStart);
1315 if (link.
isEmpty()) {
return 0; }
1323 size_t titleStart=
i;
1329 if (nl>1) {
return 0; }
1332 else if (
data[
i]==
'\\')
1336 else if (
data[
i]==c)
1347 size_t titleEnd =
i-1;
1349 while (titleEnd>titleStart &&
data[titleEnd]==
' ') titleEnd--;
1350 if (
data[titleEnd]==c)
1352 title =
data.substr(titleStart,titleEnd-titleStart);
1357 else if (
data[
i] ==
')')
break;
1382 if (nl>1) {
return 0; }
1386 if (
i>=
size) {
return 0; }
1388 link =
data.substr(linkStart,
i-linkStart);
1400 link = lr_it->second.link;
1401 title = lr_it->second.title;
1418 link = lr_it->second.link;
1419 title = lr_it->second.title;
1423 else if (content==
"TOC")
1446 while (j<
size &&
data[j]==
' ') { j++; }
1452 size_t attributesStart=
i;
1457 if (
data[
i-1]==
'\\')
1460 else if (
data[
i]==
'{')
1464 else if (
data[
i]==
'}')
1467 if (level<=0)
break;
1469 else if (
data[
i]==
'\n')
1472 if (nl>1) {
return 0; }
1477 if (
i>=
size)
return 0;
1478 size_t attributesEnd=
i;
1479 attributes =
data.substr(attributesStart,attributesEnd-attributesStart);
1488 while (pos<size && numNLsNeeded>0)
1490 if (
data[pos]==
'\n') numNLsNeeded--;
1491 else if (
data[pos]!=
' ')
1506 out+=
"@tableofcontents{html:";
1511 else if (isImageLink)
1515 if (link.
find(
"@ref ")!=-1 || link.
find(
"\\ref ")!=-1 ||
1520 writeMarkdownImage(
"html", isImageInline, explicitTitle, title, content, link, attributes, fd);
1521 writeMarkdownImage(
"latex", isImageInline, explicitTitle, title, content, link, attributes, fd);
1522 writeMarkdownImage(
"rtf", isImageInline, explicitTitle, title, content, link, attributes, fd);
1523 writeMarkdownImage(
"docbook", isImageInline, explicitTitle, title, content, link, attributes, fd);
1524 writeMarkdownImage(
"xml", isImageInline, explicitTitle, title, content, link, attributes, fd);
1546 if ((lp=link.
find(
"@ref "))!=-1 || (lp=link.
find(
"\\ref "))!=-1 || (lang==SrcLangExt::Markdown && !
isURL(link)))
1578 if (explicitTitle && !title.
isEmpty())
1588 else if ((lp=link.
find(
'#'))!=-1 || link.
find(
'/')!=-1 || link.
find(
'.')!=-1)
1590 if (lp==0 || (lp>0 && !
isURL(link) &&
Config_getEnum(MARKDOWN_ID_STYLE)==MARKDOWN_ID_STYLE_t::GITHUB))
1603 for (
int ii = 0; ii < nlTotal; ii++)
out+=
"\n";
1625 return static_cast<int>(
i);
1697 return static_cast<int>(
end+1);
1705 return static_cast<int>(
end+2);
1739 return static_cast<int>(
end);
1764 size_t l = endBlockName.
length();
1775 return static_cast<int>(
i+1+l);
1785 return static_cast<int>(endPos);
1790 if (c==
'[' || c==
']' || c==
'*' || c==
'(' || c==
')' || c==
'`' || c==
'_')
1796 else if (c==
'\\' || c==
'@')
1802 else if (c==
'-' &&
size>3 &&
data[2]==
'-' &&
data[3]==
'-')
1808 else if (c==
'-' &&
size>2 &&
data[2]==
'-')
1818 if (c==
'\\' || c==
'@')
1844 int iend = action(
data.substr(
i),
i);
1864 if (
i==
size)
return 0;
1871 int level = (c>1 && (
i>=
size ||
data[
i]==
'\n')) ? 1 : 0;
1872 if (allowAdjustLevel && level==1 &&
indentLevel==-1)
1907 if (
data[
i]==
'>') level++;
1912 bool res = (level>0 &&
i<
size && ((
data[
i-1]==
' ') ||
data[
i]==
'\n')) || (level > 1);
1933 size_t refIdStart=
i;
1936 refid =
data.substr(refIdStart,
i-refIdStart);
1937 if (refid.
isEmpty()) {
return 0; }
1951 if (
i>=
size) {
return 0; }
1958 if (linkStart==linkEnd) {
return 0; }
1959 link =
data.substr(linkStart,linkEnd-linkStart);
1961 if (link==
"@ref" || link==
"\\ref")
1965 link+=
data.substr(argStart,
i-argStart);
1986 if (c==
'\'' || c==
'"' || c==
'(')
1991 size_t titleStart=
i;
2001 title =
data.substr(titleStart,
end-titleStart);
2022 if (c!=
'*' && c!=
'-' && c!=
'_')
2034 else if (
data[
i]!=
' ')
2049 static const reg::Ex r2(R
"({#(\a[\w-]*)}\s*$)");
2051 std::string ti = title.str();
2054 std::string
id = match[1].str();
2055 title = title.
left(match.position());
2058 warn(
fileName,
lineNr,
"An automatically generated id already has the name '{}'!",
id);
2064 if (((level>0) && (level<=
Config_getInt(TOC_INCLUDE_HEADINGS))) || (
Config_getEnum(MARKDOWN_ID_STYLE)==MARKDOWN_ID_STYLE_t::GITHUB))
2067 if (pIsIdGenerated) *pIsIdGenerated=
true;
2082 int level = 0, blanks=0;
2097 if (level==1 && blanks==0)
2112 int idx=
static_cast<int>(header.
length())-1;
2113 while (idx>=0 && (header.
at(idx)==
'#' || header.
at(idx)==
' ')) idx--;
2114 header=header.
left(idx+1);
2117 if (allowAdjustLevel && level==1 &&
indentLevel==-1)
2148 while (
i<
data.size())
2159 (data[(i)]=='<' && \
2160 (data[(i)+1]=='l' || data[(i)+1]=='L') && \
2161 (data[(i)+2]=='i' || data[(i)+2]=='I') && \
2174 bool listMarkerSkipped=
FALSE;
2177 (!listMarkerSkipped &&
2196 listMarkerSkipped=
TRUE;
2213 listMarkerSkipped=
TRUE;
2217 listMarkerSkipped=
TRUE;
2223 listMarkerSkipped=
TRUE;
2225 if (
data[
i]!=
' ' && !listMarkerSkipped)
2238 size_t normalIndent = 0;
2239 while (normalIndent<
data.size() &&
data[normalIndent]==
' ') normalIndent++;
2241 size_t result = listIndent>normalIndent ? listIndent : 0;
2252 while (
i<
data.size())
2258 else if (
data[
i]==
'\n')
2274 QCString &lang,
size_t &start,
size_t &
end,
size_t &offset)
2277 const char dot =
'.';
2278 auto isAlphaChar = [ ](
char c) {
return (c>=
'A' && c<=
'Z') || (c>=
'a' && c<=
'z'); };
2279 auto isAlphaNChar = [ ](
char c) {
return (c>=
'A' && c<=
'Z') || (c>=
'a' && c<=
'z') || (c>=
'0' && c<=
'9') || (c==
'+'); };
2280 auto isLangChar = [&](
char c) {
return c==dot || isAlphaChar(c); };
2288 if (indent>=refIndent+4)
2290 AUTO_TRACE_EXIT(
"result=false: content is part of code block indent={} refIndent={}",indent,refIndent);
2295 while (
i<
size &&
data[
i]==tildaChar) startTildes++,
i++;
2298 AUTO_TRACE_EXIT(
"result=false: no fence marker found #tildes={}",startTildes);
2309 lang =
data.substr(startLang,
i-startLang);
2327 lang =
data.substr(startLang,
i-startLang);
2337 if (
data[
i]==tildaChar)
2341 while (
i<
size &&
data[
i]==tildaChar) endTildes++,
i++;
2344 if (endTildes==startTildes)
2347 AUTO_TRACE_EXIT(
"result=true: found end marker at offset {} lang='{}'",offset,lang);
2370 AUTO_TRACE_EXIT(
"result={}: line is not indented enough {}<4",
false,indent0);
2373 if (indent0>=
size ||
data[indent0]==
'\n')
2375 AUTO_TRACE_EXIT(
"result={}: only spaces at the end of a comment block",
false);
2382 int offset_i =
static_cast<int>(offset);
2386 int j =
static_cast<int>(
i)-offset_i-1;
2391 nl_pos[nl++]=j+
static_cast<int>(nl_size);
2397 if (
i==0 && nl==2) nl_pos[nl++]=-offset_i;
2408 if (!
isEmptyLine(std::string_view(
data.data()+nl_pos[1],nl_pos[0]-nl_pos[1]-1)))
2417 std::string_view(
data.data()+nl_pos[2],nl_pos[1]-nl_pos[2])));
2423 AUTO_TRACE_EXIT(
"result={}: code block if indent difference >4 spaces",res);
2430 if (nl==1 && !
isEmptyLine(std::string_view(
data.data()-offset,offset-1)))
2438 AUTO_TRACE_EXIT(
"result={}: code block if indent difference >4 spaces",res);
2466 if (j>0 &&
i>0)
i--;
2467 while (
i>0 &&
data[
i]==
' ')
i--;
2478 if (
data[
i]==
'|' && (
i==0 ||
data[
i-1]!=
'\\')) columns++;
2479 if (columns==1) columns++;
2483 if (n==2 && columns==0)
2495 size_t cc0=0, start=0,
end=0;
2499 if (
i>=
data.size() || cc0<1)
2520 AUTO_TRACE_EXIT(
"result=false: different number of columns as previous line {}!={}",cc1,cc0);
2537 size_t columns=0, start=0,
end=0;
2539 size_t headerStart = start;
2540 size_t headerEnd =
end;
2546 std::vector<int> columnAlignment(columns);
2548 bool leftMarker=
false, rightMarker=
false, startFound=
false;
2554 if (
data[j]==
':') { leftMarker=
TRUE; startFound=
TRUE; }
2559 else if (
data[j]==
':') rightMarker=
TRUE;
2560 if (j<=
end+
i && (
data[j]==
'|' && (j==0 ||
data[j-1]!=
'\\')))
2584 std::vector<std::vector<TableCell> > tableContents;
2586 size_t m = headerStart;
2587 std::vector<TableCell> headerContents(columns);
2588 for (k=0;k<columns;k++)
2590 while (m<=headerEnd && (
data[m]!=
'|' || (m>0 &&
data[m-1]==
'\\')))
2592 headerContents[k].cellText +=
data[m++];
2597 headerContents[k].colSpan = headerContents[k].cellText.isEmpty();
2598 headerContents[k].cellText = headerContents[k].cellText.stripWhiteSpace();
2600 tableContents.push_back(headerContents);
2606 if (cc!=columns)
break;
2610 std::vector<TableCell> rowContents(columns);
2613 if (j<=
end+
i && (
data[j]==
'|' && (j==0 ||
data[j-1]!=
'\\')))
2617 rowContents[k].colSpan = rowContents[k].cellText.isEmpty();
2618 rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace();
2623 rowContents[k].cellText +=
data[j];
2629 rowContents[k].colSpan = rowContents[k].cellText.isEmpty();
2630 rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace();
2631 tableContents.push_back(rowContents);
2637 out+=
"<table class=\"markdownTable\">";
2638 QCString cellTag(
"th"), cellClass(
"class=\"markdownTableHead");
2639 for (
size_t row = 0; row < tableContents.size(); row++)
2645 out+=
"\n<tr class=\"markdownTableRowOdd\">";
2649 out+=
"\n<tr class=\"markdownTableRowEven\">";
2654 out+=
"\n <tr class=\"markdownTableHead\">";
2656 for (
size_t c = 0; c < columns; c++)
2659 QCString cellText(tableContents[row][c].cellText);
2665 if (tableContents[row][c].cellText ==
"^")
2669 if (tableContents[row][c].colSpan)
2671 int cr =
static_cast<int>(c);
2672 while ( cr >= 0 && tableContents[row][cr].colSpan)
2676 if (cr >= 0 && tableContents[row][cr].cellText ==
"^")
continue;
2678 size_t rowSpan = 1, spanRow = row+1;
2679 while ((spanRow < tableContents.size()) &&
2680 (tableContents[spanRow][c].cellText ==
"^"))
2686 out+=
" <" + cellTag +
" " + cellClass;
2688 switch (columnAlignment[c])
2700 out+=
" rowspan=\"" + spanStr +
"\"";
2706 while ((c+1 < columns) && tableContents[row][c+1].colSpan)
2715 out+=
" colspan=\"" + spanStr +
"\"";
2719 out+=
"> " + cellText +
" \\ilinebr </" + cellTag +
">";
2722 cellClass =
"class=\"markdownTableBody";
2743 if (
i>=
data.size()) {
return 0; }
2744 if (
i<2) {
return 0; }
2745 bool res = (j>0 &&
data[
i-1]==
' ' &&
data[
i-2]==
' ');
2785 out+=
"</"+hTag+
">\n";
2788 else if (
data.size()>0)
2790 size_t tmpSize =
data.size();
2791 if (
data[
data.size()-1] ==
'\n') tmpSize--;
2796 out+=
"\\ilinebr<br>";
2798 if (tmpSize !=
data.size())
out+=
'\n';
2804 {
"[!note]",
"\\note" },
2805 {
"[!warning]",
"\\warning" },
2806 {
"[!tip]",
"\\remark" },
2807 {
"[!caution]",
"\\attention" },
2808 {
"[!important]",
"\\important" }
2818 std::string startCmd;
2819 int isGitHubAlert =
false;
2820 int isGitHubFirst =
false;
2832 if (
data[j]==
'>') { level++; indent=j+1; }
2833 else if (j>0 &&
data[j-1]==
'>') indent=j+1;
2836 if (indent>0 && j>0 &&
data[j-1]==
'>' &&
2854 isGitHubAlert =
true;
2855 isGitHubFirst =
true;
2856 startCmd = it->second;
2861 if (level!=1 || !isGitHubAlert)
2863 for (
int l=curLevel;l<level-1;l++)
2865 out+=
"<blockquote>";
2867 out +=
"<blockquote>‍";
2869 else if (!startCmd.empty())
2871 out += startCmd +
" ";
2874 else if (level<curLevel)
2877 if (level==0 && isGitHubAlert)
2883 out +=
"</blockquote>\\ilinebr ";
2892 if (curLevel!=0 || !isGitHubAlert)
2894 std::string_view txt =
data.substr(indent,
end-indent);
2897 if (!isGitHubFirst)
out +=
"<br>";
2904 isGitHubFirst =
false;
2919 for (
int l=0;l<curLevel;l++)
2921 out+=
"</blockquote>";
2936 size_t locStart =
i;
2937 if (
i>offset) locStart--;
2952 location=
data.substr(locStart,
i-locStart);
2954 while (indent>0 &&
i<
size &&
data[
i]==
' ')
i++,indent--;
2969 out+=
"@iverbatim\n";
2971 std::string location;
2979 while (j<
end &&
data[j]==
' ') j++,indent++;
2989 while (emptyLines>0)
2997 std::string lineLoc;
3010 out+=
"@endiverbatim";
3011 if (!location.empty())
3019 while (emptyLines>0)
3036 size_t nb=0,
end=offset+1, j=0;
3049 size_t l = endBlockName.
length();
3083 else if (nb==0 &&
data[
end-1]==
'`')
3087 else if (nb>0 &&
data[
end-1]==
'`')
3104 size_t blockStart,
size_t blockEnd)
3107 if (!lang.empty() && lang[0]==
'.') lang=lang.substr(1);
3131 size_t pi=std::string::npos;
3132 bool newBlock =
false;
3133 bool insideList =
false;
3134 size_t currentIndent = refIndent;
3135 size_t listIndent = refIndent;
3143 size_t lineIndent=0;
3144 while (lineIndent<
end &&
data[
i+lineIndent]==
' ') lineIndent++;
3150 if (insideList && lineIndent<currentIndent)
3153 currentIndent = refIndent;
3161 if (listIndent<currentIndent+4)
3165 currentIndent = listIndent;
3172 currentIndent = listIndent;
3181 if (pi!=std::string::npos)
3183 size_t blockStart=0, blockEnd=0, blockOffset=0;
3186 auto addSpecialCommand = [&](
const QCString &startCmd,
const QCString &endCmd)
3188 size_t cmdPos = pi+blockStart+1;
3189 QCString pl =
data.substr(cmdPos,blockEnd-blockStart-1);
3195 if (pl[ii]==
'\n') nl++;
3198 bool addNewLines =
false;
3200 (pl[ii]!=
'\\' && pl[ii]!=
'@') ||
3209 pl =
"@"+startCmd+
"\n" + pl +
"@"+endCmd;
3210 addNewLines =
false;
3225 if (addNewLines)
for (
int j=0;j<nl;j++)
out+=
'\n';
3227 if (addNewLines)
out+=
'\n';
3232 addSpecialCommand(
"startuml",
"enduml");
3236 addSpecialCommand(
"dot",
"enddot");
3238 else if (lang==
"msc")
3240 addSpecialCommand(
"msc",
"endmsc");
3247 pi=std::string::npos;
3254 pi=std::string::npos;
3267 if (pi!=std::string::npos && pi<
size)
3289 size_t pi = std::string::npos;
3305 size_t currentIndent = indent;
3306 size_t listIndent = indent;
3307 bool insideList =
false;
3308 bool newBlock =
false;
3311 while (
i<
data.size())
3316 size_t lineIndent=0;
3318 while (lineIndent<
end &&
data[
i+lineIndent]==
' ') lineIndent++;
3324 if (insideList && lineIndent<currentIndent)
3327 currentIndent = indent;
3335 if (listIndent<currentIndent+4)
3339 currentIndent = listIndent;
3346 currentIndent = listIndent;
3358 if (pi!=std::string::npos)
3360 size_t blockStart=0, blockEnd=0, blockOffset=0;
3362 size_t blockIndent = currentIndent;
3380 size_t l = endBlockName.
length();
3381 while (
i+l<
data.size())
3401 while (pi<
data.size() &&
data[pi]==
' ') pi++;
3409 out+=level==1?
"@section ":
"@subsection ";
3417 out+=level==1?
"<h1>":
"<h2>";
3419 out+=level==1?
"\n</h1>\n":
"\n</h2>\n";
3426 pi=std::string::npos;
3445 pi=std::string::npos;
3453 pi=std::string::npos;
3460 pi=std::string::npos;
3473 if (pi!=std::string::npos && pi<
data.size())
3492#define OPC(x) if (literal_at(data,#x " ") || literal_at(data,#x "\n")) return true
3493 OPC(dir);
OPC(defgroup);
OPC(addtogroup);
OPC(weakgroup);
OPC(ingroup);
3496 OPC(protocol);
OPC(category);
OPC(
union);
OPC(
struct);
OPC(interface);
3497 OPC(idlexcept);
OPC(file);
3507 std::string_view
data(docs.
str());
3557 std::string_view
data(docs_org.
str());
3562 if (
data[
i]==
'\n') prepend++;
3567 while (end1<
size &&
data[end1-1]!=
'\n') end1++;
3574 while (end2<
size &&
data[end2-1]!=
'\n') end2++;
3577 title =
data.substr(
i,end1-
i-1);
3578 docs+=
"\n\n"+docs_org.
mid(end2);
3579 id =
prv->extractTitleId(title, 0, &isIdGenerated);
3588 docs+=docs_org.
mid(end1);
3593 id =
prv->extractTitleId(title, 0, &isIdGenerated);
3604 if (input.
isEmpty())
return input;
3609 if (
s.at(
s.length()-1)!=
'\n')
s +=
"\n";
3614 s =
prv->processQuotations(
s.view(),refIndent);
3618 s =
prv->processBlocks(
s.view(),refIndent);
3623 prv->out.reserve(
s.length());
3624 prv->processInline(
s.view());
3636 const char *p = result.
data();
3639 while (*p==
' ') p++;
3640 while (*p==
'\n') {startNewlines++;p++;};
3643 if (p>result.
data())
3646 result = result.
mid(
static_cast<int>(p-result.
data()));
3659 if (
i!=-1) baseFn = baseFn.
left(
i);
3683 const char *fileBuf,
3684 const std::shared_ptr<Entry> &root,
3687 std::shared_ptr<Entry> current = std::make_shared<Entry>();
3689 current->lang = SrcLangExt::Markdown;
3690 current->fileName = fileName;
3691 current->docFile = fileName;
3692 current->docLine = 1;
3698 bool isIdGenerated =
false;
3706 int indentLevel=title.
isEmpty() ? 0 : -1;
3713 bool wasEmpty =
id.isEmpty();
3714 if (wasEmpty)
id = mdFileNameId;
3720 if (!mdfileAsMainPage.
isEmpty() &&
3724 docs.
prepend(
"@ianchor{" + title +
"} " +
id +
"\\ilinebr ");
3725 docs.
prepend(
"@mainpage "+title+
"\\ilinebr ");
3727 else if (
id==
"mainpage" ||
id==
"index")
3729 if (title.
isEmpty()) title = titleFn;
3730 docs.
prepend(
"@ianchor{" + title +
"} " +
id +
"\\ilinebr ");
3731 docs.
prepend(
"@mainpage "+title+
"\\ilinebr ");
3733 else if (isSubdirDocs)
3737 docs.
prepend(
"@section " + generatedId +
" " + title +
"\\ilinebr ");
3739 docs.
prepend(
"@dir\\ilinebr ");
3750 docs.
prepend(
"@ianchor{" + title +
"} " +
id +
"\\ilinebr @ianchor{" + relFileName +
"} " + mdFileNameId +
"\\ilinebr ");
3752 else if (!generatedId.
isEmpty())
3754 docs.
prepend(
"@ianchor " + generatedId +
"\\ilinebr ");
3756 else if (
Config_getEnum(MARKDOWN_ID_STYLE)==MARKDOWN_ID_STYLE_t::GITHUB)
3759 docs.
prepend(
"@ianchor{" + title +
"} " + autoId +
"\\ilinebr ");
3761 docs.
prepend(
"@page "+
id+
" "+title+
"\\ilinebr ");
3763 for (
int i = 0;
i < prepend;
i++) docs.
prepend(
"\n");
3768 static const reg::Ex re(R
"([ ]*[\\@]page\s+(\a[\w-]*)(\s*[^\n]*)\n)");
3770 std::string s = docs.str();
3773 QCString orgLabel = match[1].str();
3774 QCString orgTitle = match[2].str();
3777 docs = docs.
left(match[1].position())+
3780 "\\ilinebr @ianchor{" + orgTitle +
"} "+orgLabel+
"\n"+
3792 p->commentScanner.enterFile(fileName,lineNr);
3794 bool needsEntry =
false;
3798 while (
p->commentScanner.parseCommentBlock(
3816 QCString docFile = current->docFile;
3817 root->moveToSubEntryAndRefresh(current);
3818 current->lang = SrcLangExt::Markdown;
3819 current->docFile = docFile;
3820 current->docLine = lineNr;
3825 root->moveToSubEntryAndKeep(current);
3827 p->commentScanner.leaveFile(fileName,lineNr);
#define eol
The end of line string for this machine.
static AnchorGenerator & instance()
Returns the singleton instance.
static std::string addPrefixIfNeeded(const std::string &anchor)
std::string generate(const std::string &title)
generates an anchor for a section with title.
Clang parser object for a single translation unit, which consists of a source file and the directly o...
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
static ParserManager * parserManager
static FileNameLinkedMap * imageNameLinkedMap
A model of a file symbol.
Minimal replacement for QFileInfo.
std::string fileName() const
std::string absFilePath() const
Helper class to process markdown formatted text.
std::unique_ptr< Private > prv
void setIndentLevel(int level)
QCString extractPageTitle(QCString &docs, QCString &id, int &prepend, bool &isIdGenerated)
Markdown(const QCString &fileName, int lineNr, int indentLevel=0)
QCString process(const QCString &input, int &startNewlines, bool fromParseInput=false)
void parseInput(const QCString &fileName, const char *fileBuf, const std::shared_ptr< Entry > &root, ClangTUParser *clangParser) override
Parses a single input file with the goal to build an Entry tree.
~MarkdownOutlineParser() override
void parsePrototype(const QCString &text) override
Callback function called by the comment block scanner.
std::unique_ptr< Private > p
This is an alternative implementation of QCString.
int find(char c, int index=0, bool cs=TRUE) const
QCString & prepend(const char *s)
size_t length() const
Returns the length of the string, not counting the 0-terminator.
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
bool endsWith(const char *s) const
char & at(size_t i)
Returns a reference to the character at index i.
bool isEmpty() const
Returns TRUE iff the string is empty.
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
const std::string & str() const
QCString & setNum(short n)
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
QCString right(size_t len) const
size_t size() const
Returns the length of the string, not counting the 0-terminator.
QCString & sprintf(const char *format,...)
int findRev(char c, int index=-1, bool cs=TRUE) const
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
std::string_view view() const
QCString left(size_t len) const
static constexpr int Section
static constexpr int MaxLevel
static constexpr int Subsection
static constexpr int Subsubsection
static constexpr int MinLevel
static constexpr int Paragraph
static constexpr int Subsubparagraph
static constexpr int Subparagraph
Class representing a regular expression.
Object representing the matching results.
#define Config_getInt(name)
#define Config_getBool(name)
#define Config_getString(name)
#define Config_getEnum(name)
std::vector< std::string > StringVector
DirIterator end(const DirIterator &) noexcept
#define AUTO_TRACE_ADD(...)
#define AUTO_TRACE_EXIT(...)
static bool isOtherPage(std::string_view data)
static bool hasLineBreak(std::string_view data)
@ explicitMainPage
docs start with a mainpage command
@ explicitPage
docs start with a page command
@ notExplicit
docs doesn't start with either page or mainpage
@ explicitOtherPage
docs start with a dir / defgroup / addtogroup command
static bool isBlockQuote(std::string_view data, size_t indent)
returns true if this line starts a block quote
static size_t isLinkRef(std::string_view data, QCString &refid, QCString &link, QCString &title)
returns end of the link ref if this is indeed a link reference.
static QCString escapeDoubleQuotes(const QCString &s)
static bool isEndOfList(std::string_view data)
static size_t computeIndentExcludingListMarkers(std::string_view data)
static Alignment markersToAlignment(bool leftMarker, bool rightMarker)
helper function to convert presence of left and/or right alignment markers to an alignment value
static QCString escapeSpecialChars(const QCString &s)
static bool isCodeBlock(std::string_view data, size_t offset, size_t &indent)
static bool isEmptyLine(std::string_view data)
#define AUTO_TRACE_EXIT(...)
static size_t findTableColumns(std::string_view data, size_t &start, size_t &end, size_t &columns)
Finds the location of the table's contains in the string data.
const size_t codeBlockIndent
static ExplicitPageResult isExplicitPage(const QCString &docs)
#define ignoreCloseEmphChar(c, cn)
static const std::unordered_map< std::string, std::string > g_quotationHeaderMap
#define isOpenEmphChar(c)
static bool isFencedCodeBlock(std::string_view data, size_t refIndent, QCString &lang, size_t &start, size_t &end, size_t &offset)
static size_t isListMarker(std::string_view data)
static bool isHRuler(std::string_view data)
static QCString getFilteredImageAttributes(std::string_view fmt, const QCString &attrs)
parse the image attributes and return attributes for given format
bool skipOverFileAndLineCommands(std::string_view data, size_t indent, size_t &offset, std::string &location)
static bool isTableBlock(std::string_view data)
Returns TRUE iff data points to the start of a table block.
size_t isNewline(std::string_view data)
QCString markdownFileNameToId(const QCString &fileName)
processes string s and converts markdown into doxygen/html commands.
#define warn(file, line, fmt,...)
bool isAbsolutePath(const QCString &fileName)
const char * strnstr(const char *haystack, const char *needle, size_t haystack_len)
QCString trunc(const QCString &s, size_t numChars=15)
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Portable versions of functions that are platform dependent.
static void decrLevel(yyscan_t yyscanner)
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
int qstrncmp(const char *str1, const char *str2, size_t len)
const char * qPrint(const char *s)
Some helper functions for std::string.
bool literal_at(const char *data, const char(&str)[N])
returns TRUE iff data points to a substring that matches string literal str
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
LinkRef(const QCString &l, const QCString &t)
int processEmphasis1(std::string_view data, char c)
process single emphasis
int processQuoted(std::string_view data, size_t offset)
Process quoted section "...", can contain one embedded newline.
void writeMarkdownImage(std::string_view fmt, bool inline_img, bool explicitTitle, const QCString &title, const QCString &content, const QCString &link, const QCString &attributes, const FileDef *fd)
size_t writeTableBlock(std::string_view data)
size_t writeBlockQuote(std::string_view data)
size_t isSpecialCommand(std::string_view data, size_t offset)
std::function< int(std::string_view, size_t)> Action_t
int processEmphasis3(std::string_view data, char c)
Parsing triple emphasis.
int processCodeSpan(std::string_view data, size_t offset)
` parsing a code span (assuming codespan != 0)
int processSpecialCommand(std::string_view data, size_t offset)
QCString extractTitleId(QCString &title, int level, bool *pIsIdGenerated=nullptr)
void writeFencedCodeBlock(std::string_view data, std::string_view lang, size_t blockStart, size_t blockEnd)
int isHeaderline(std::string_view data, bool allowAdjustLevel)
returns whether the line is a setext-style hdr underline
size_t findEmphasisChar(std::string_view, char c, size_t c_size)
looks for the next emph char, skipping other constructs, and stopping when either it is found,...
std::unordered_map< std::string, LinkRef > linkRefs
void addStrEscapeUtf8Nbsp(std::string_view data)
QCString isBlockCommand(std::string_view data, size_t offset)
size_t writeCodeBlock(std::string_view, size_t refIndent)
int processHtmlTag(std::string_view data, size_t offset)
QCString processQuotations(std::string_view data, size_t refIndent)
QCString processBlocks(std::string_view data, size_t indent)
int processEmphasis(std::string_view data, size_t offset)
int processLink(std::string_view data, size_t offset)
int processHtmlTagWrite(std::string_view data, size_t offset, bool doWrite)
Process a HTML tag.
int isAtxHeader(std::string_view data, QCString &header, QCString &id, bool allowAdjustLevel, bool *pIsIdGenerated=nullptr)
size_t findEndOfLine(std::string_view data, size_t offset)
int processEmphasis2(std::string_view data, char c)
process double emphasis
void processInline(std::string_view data)
int processNmdash(std::string_view data, size_t offset)
Process ndash and mdashes.
void writeOneLineHeaderOrRuler(std::string_view data)
std::array< Action_t, 256 > actions
CommentScanner commentScanner
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
QCString stripIndentation(const QCString &s, bool skipFirstLine)
QCString escapeCharsInString(const QCString &name, bool allowDots, bool allowUnderscore)
QCString stripExtensionGeneral(const QCString &fName, const QCString &ext)
bool isURL(const QCString &url)
Checks whether the given url starts with a supported protocol.
static QCString stripFromPath(const QCString &p, const StringVector &l)
QCString detab(const QCString &s, size_t &refIndent)
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
QCString externalLinkTarget(const bool parent)
QCString getFileNameExtension(const QCString &fn)
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
A bunch of utility functions.