Skip to content

Commit c740190

Browse files
committed
Refactoring: modernize markdown code a bit
1 parent b0b6a53 commit c740190

File tree

2 files changed

+94
-80
lines changed

2 files changed

+94
-80
lines changed

src/markdown.cpp

Lines changed: 90 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -74,41 +74,50 @@ enum class ExplicitPageResult
7474
//-----------
7575

7676
// is character c part of an identifier?
77-
#define isIdChar(c) \
78-
((c>='a' && c<='z') || \
79-
(c>='A' && c<='Z') || \
80-
(c>='0' && c<='9') || \
81-
(static_cast<unsigned char>(c)>=0x80)) // unicode characters
77+
static constexpr bool isIdChar(char c)
78+
{
79+
return (c>='a' && c<='z') ||
80+
(c>='A' && c<='Z') ||
81+
(c>='0' && c<='9') ||
82+
(static_cast<unsigned char>(c)>=0x80); // unicode characters
83+
}
8284

8385
// is character allowed right at the beginning of an emphasis section
84-
#define extraChar(c) \
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=='`')
86+
static constexpr bool extraChar(char c)
87+
{
88+
return c=='-' || c=='+' || c=='!' || c=='?' || c=='$' || c=='@' ||
89+
c=='&' || c=='*' || c=='_' || c=='%' || c=='[' || c=='(' ||
90+
c=='.' || c=='>' || c==':' || c==',' || c==';' || c=='\'' ||
91+
c=='"' || c=='`';
92+
}
9193

9294
// is character c allowed before an emphasis section
93-
#define isOpenEmphChar(c) \
94-
(c=='\n' || c==' ' || c=='\'' || c=='<' || \
95-
c=='>' || c=='{' || c=='(' || c=='[' || \
96-
c==',' || c==':' || c==';')
95+
static constexpr bool isOpenEmphChar(char c)
96+
{
97+
return c=='\n' || c==' ' || c=='\'' || c=='<' ||
98+
c=='>' || c=='{' || c=='(' || c=='[' ||
99+
c==',' || c==':' || c==';';
100+
}
97101

98102
// test for non breakable space (UTF-8)
99-
#define isUtf8Nbsp(c1,c2) \
100-
(c1==static_cast<char>(0xc2) && c2==static_cast<char>(0xa0))
101-
102-
#define isAllowedEmphStr(data,offset) \
103-
((offset>0 && !isOpenEmphChar(data.data()[-1])) && \
104-
(offset>1 && !isUtf8Nbsp(data.data()[-2],data.data()[-1])))
105-
106-
// is character at position i in data an escape that prevents ending an emphasis section
107-
// so for example *bla (*.txt) is cool*
108-
#define ignoreCloseEmphChar(c,cn) \
109-
(c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || \
110-
c=='\\' || \
111-
c=='@')
103+
static constexpr bool isUtf8Nbsp(char c1,char c2)
104+
{
105+
return c1==static_cast<char>(0xc2) && c2==static_cast<char>(0xa0);
106+
}
107+
108+
static constexpr bool isAllowedEmphStr(const std::string_view &data,size_t offset)
109+
{
110+
return ((offset>0 && !isOpenEmphChar(data.data()[-1])) &&
111+
(offset>1 && !isUtf8Nbsp(data.data()[-2],data.data()[-1])));
112+
}
113+
114+
// is character c an escape that prevents ending an emphasis section
115+
// so for example *bla (*.txt) is cool*, the c=='(' prevents '*' from ending the emphasis section.
116+
static constexpr bool ignoreCloseEmphChar(char c,char cn)
117+
{
118+
return c=='(' || c=='{' || c=='[' || (c=='<' && cn!='/') || c=='\\' || c=='@';
119+
}
120+
112121
//----------
113122

114123
struct TableCell
@@ -120,22 +129,7 @@ struct TableCell
120129

121130
struct Markdown::Private
122131
{
123-
Private(const QCString &fn,int line,int indent)
124-
: fileName(fn), lineNr(line), indentLevel(indent)
125-
{
126-
// setup callback table for special characters
127-
actions[static_cast<unsigned int>('_')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
128-
actions[static_cast<unsigned int>('*')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
129-
actions[static_cast<unsigned int>('~')] = [this](std::string_view data,size_t offset) { return processEmphasis (data,offset); };
130-
actions[static_cast<unsigned int>('`')] = [this](std::string_view data,size_t offset) { return processCodeSpan (data,offset); };
131-
actions[static_cast<unsigned int>('\\')]= [this](std::string_view data,size_t offset) { return processSpecialCommand(data,offset); };
132-
actions[static_cast<unsigned int>('@')] = [this](std::string_view data,size_t offset) { return processSpecialCommand(data,offset); };
133-
actions[static_cast<unsigned int>('[')] = [this](std::string_view data,size_t offset) { return processLink (data,offset); };
134-
actions[static_cast<unsigned int>('!')] = [this](std::string_view data,size_t offset) { return processLink (data,offset); };
135-
actions[static_cast<unsigned int>('<')] = [this](std::string_view data,size_t offset) { return processHtmlTag (data,offset); };
136-
actions[static_cast<unsigned int>('-')] = [this](std::string_view data,size_t offset) { return processNmdash (data,offset); };
137-
actions[static_cast<unsigned int>('"')] = [this](std::string_view data,size_t offset) { return processQuoted (data,offset); };
138-
}
132+
Private(const QCString &fn,int line,int indent) : fileName(fn), lineNr(line), indentLevel(indent) { }
139133

140134
QCString processQuotations(std::string_view data,size_t refIndent);
141135
QCString processBlocks(std::string_view data,size_t indent);
@@ -177,16 +171,33 @@ struct Markdown::Private
177171
QCString link;
178172
QCString title;
179173
};
180-
using Action_t = std::function<int(std::string_view,size_t)>;
181174

182175
std::unordered_map<std::string,LinkRef> linkRefs;
183176
QCString fileName;
184177
int lineNr = 0;
185178
int indentLevel=0; // 0 is outside markdown, -1=page level
186179
QCString out;
187-
std::array<Action_t,256> actions;
188180
};
189181

182+
Markdown::ActionTable_t Markdown::fill_table()
183+
{
184+
Markdown::ActionTable_t a{};
185+
a[static_cast<unsigned int>('_')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processEmphasis (data,offset); };
186+
a[static_cast<unsigned int>('*')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processEmphasis (data,offset); };
187+
a[static_cast<unsigned int>('~')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processEmphasis (data,offset); };
188+
a[static_cast<unsigned int>('`')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processCodeSpan (data,offset); };
189+
a[static_cast<unsigned int>('\\')]= [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processSpecialCommand(data,offset); };
190+
a[static_cast<unsigned int>('@')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processSpecialCommand(data,offset); };
191+
a[static_cast<unsigned int>('[')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processLink (data,offset); };
192+
a[static_cast<unsigned int>('!')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processLink (data,offset); };
193+
a[static_cast<unsigned int>('<')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processHtmlTag (data,offset); };
194+
a[static_cast<unsigned int>('-')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processNmdash (data,offset); };
195+
a[static_cast<unsigned int>('"')] = [](Markdown::Private &obj,std::string_view data,size_t offset) { return obj.processQuoted (data,offset); };
196+
return a;
197+
}
198+
Markdown::ActionTable_t Markdown::actions = Markdown::fill_table();
199+
200+
190201
Markdown::Markdown(const QCString &fileName,int lineNr,int indentLevel)
191202
: prv(std::make_unique<Private>(fileName,lineNr,indentLevel))
192203
{
@@ -198,15 +209,14 @@ Markdown::~Markdown() = default;
198209

199210
void Markdown::setIndentLevel(int level) { prv->indentLevel = level; }
200211

201-
202-
enum Alignment { AlignNone, AlignLeft, AlignCenter, AlignRight };
212+
enum class Alignment { None, Left, Center, Right };
203213

204214

205215
//---------- constants -------
206216
//
207-
const char *g_utf8_nbsp = "\xc2\xa0"; // UTF-8 nbsp
208-
const char *g_doxy_nbsp = "&_doxy_nbsp;"; // doxygen escape command for UTF-8 nbsp
209-
const size_t codeBlockIndent = 4;
217+
static const char *g_utf8_nbsp = "\xc2\xa0"; // UTF-8 nbsp
218+
static const char *g_doxy_nbsp = "&_doxy_nbsp;"; // doxygen escape command for UTF-8 nbsp
219+
static const size_t codeBlockIndent = 4;
210220

211221
//---------- helpers -------
212222

@@ -307,23 +317,23 @@ static QCString escapeSpecialChars(const QCString &s)
307317
/** helper function to convert presence of left and/or right alignment markers
308318
* to an alignment value
309319
*/
310-
static Alignment markersToAlignment(bool leftMarker,bool rightMarker)
320+
static constexpr Alignment markersToAlignment(bool leftMarker,bool rightMarker)
311321
{
312322
if (leftMarker && rightMarker)
313323
{
314-
return AlignCenter;
324+
return Alignment::Center;
315325
}
316326
else if (leftMarker)
317327
{
318-
return AlignLeft;
328+
return Alignment::Left;
319329
}
320330
else if (rightMarker)
321331
{
322-
return AlignRight;
332+
return Alignment::Right;
323333
}
324334
else
325335
{
326-
return AlignNone;
336+
return Alignment::None;
327337
}
328338
}
329339

@@ -377,23 +387,24 @@ static QCString getFilteredImageAttributes(std::string_view fmt, const QCString
377387
// \startuml..\enduml
378388
QCString Markdown::Private::isBlockCommand(std::string_view data,size_t offset)
379389
{
390+
QCString result;
380391
AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
381392

382393
using EndBlockFunc = QCString (*)(const std::string &,bool,char);
383394

384-
static const auto getEndBlock = [](const std::string &blockName,bool,char) -> QCString
395+
static constexpr auto getEndBlock = [](const std::string &blockName,bool,char) -> QCString
385396
{
386397
return "end"+blockName;
387398
};
388-
static const auto getEndCode = [](const std::string &blockName,bool openBracket,char) -> QCString
399+
static constexpr auto getEndCode = [](const std::string &blockName,bool openBracket,char) -> QCString
389400
{
390401
return openBracket ? QCString("}") : "end"+blockName;
391402
};
392-
static const auto getEndUml = [](const std::string &/* blockName */,bool,char) -> QCString
403+
static constexpr auto getEndUml = [](const std::string &/* blockName */,bool,char) -> QCString
393404
{
394405
return "enduml";
395406
};
396-
static const auto getEndFormula = [](const std::string &/* blockName */,bool,char nextChar) -> QCString
407+
static constexpr auto getEndFormula = [](const std::string &/* blockName */,bool,char nextChar) -> QCString
397408
{
398409
switch (nextChar)
399410
{
@@ -428,14 +439,13 @@ QCString Markdown::Private::isBlockCommand(std::string_view data,size_t offset)
428439
const size_t size = data.size();
429440
bool openBracket = offset>0 && data.data()[-1]=='{';
430441
bool isEscaped = offset>0 && (data.data()[-1]=='\\' || data.data()[-1]=='@');
431-
if (isEscaped) return QCString();
442+
if (isEscaped) return result;
432443

433444
size_t end=1;
434445
while (end<size && (data[end]>='a' && data[end]<='z')) end++;
435-
if (end==1) return QCString();
446+
if (end==1) return result;
436447
std::string blockName(data.substr(1,end-1));
437448
auto it = blockNames.find(blockName);
438-
QCString result;
439449
if (it!=blockNames.end()) // there is a function assigned
440450
{
441451
result = it->second(blockName, openBracket, end<size ? data[end] : 0);
@@ -450,7 +460,7 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
450460

451461
using EndCmdFunc = size_t (*)(std::string_view,size_t);
452462

453-
static const auto endOfLine = [](std::string_view data_,size_t offset_) -> size_t
463+
static constexpr auto endOfLine = [](std::string_view data_,size_t offset_) -> size_t
454464
{
455465
// skip until the end of line (allowing line continuation characters)
456466
char lc = 0;
@@ -464,7 +474,7 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
464474
return offset_;
465475
};
466476

467-
static const auto endOfLabels = [](std::string_view data_,size_t offset_,bool multi_) -> size_t
477+
static constexpr auto endOfLabels = [](std::string_view data_,size_t offset_,bool multi_) -> size_t
468478
{
469479
if (offset_<data_.size() && data_[offset_]==' ') // we expect a space before the label
470480
{
@@ -510,12 +520,12 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
510520
return 0;
511521
};
512522

513-
static const auto endOfLabel = [](std::string_view data_,size_t offset_) -> size_t
523+
static constexpr auto endOfLabel = [](std::string_view data_,size_t offset_) -> size_t
514524
{
515525
return endOfLabels(data_,offset_,false);
516526
};
517527

518-
static const auto endOfLabelOpt = [](std::string_view data_,size_t offset_) -> size_t
528+
static constexpr auto endOfLabelOpt = [](std::string_view data_,size_t offset_) -> size_t
519529
{
520530
size_t index=offset_;
521531
if (index<data_.size() && data_[index]==' ') // skip over optional spaces
@@ -534,7 +544,7 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
534544
return endOfLabel(data_,offset_);
535545
};
536546

537-
static const auto endOfParam = [](std::string_view data_,size_t offset_) -> size_t
547+
static constexpr auto endOfParam = [](std::string_view data_,size_t offset_) -> size_t
538548
{
539549
size_t index=offset_;
540550
if (index<data_.size() && data_[index]==' ') // skip over optional spaces
@@ -553,12 +563,12 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
553563
return endOfLabels(data_,offset_,true);
554564
};
555565

556-
static const auto endOfRetVal = [](std::string_view data_,size_t offset_) -> size_t
566+
static constexpr auto endOfRetVal = [](std::string_view data_,size_t offset_) -> size_t
557567
{
558568
return endOfLabels(data_,offset_,true);
559569
};
560570

561-
static const auto endOfFuncLike = [](std::string_view data_,size_t offset_,bool allowSpaces) -> size_t
571+
static constexpr auto endOfFuncLike = [](std::string_view data_,size_t offset_,bool allowSpaces) -> size_t
562572
{
563573
if (offset_<data_.size() && data_[offset_]==' ') // we expect a space before the name
564574
{
@@ -591,12 +601,12 @@ size_t Markdown::Private::isSpecialCommand(std::string_view data,size_t offset)
591601
return 0;
592602
};
593603

594-
static const auto endOfFunc = [](std::string_view data_,size_t offset_) -> size_t
604+
static constexpr auto endOfFunc = [](std::string_view data_,size_t offset_) -> size_t
595605
{
596606
return endOfFuncLike(data_,offset_,true);
597607
};
598608

599-
static const auto endOfGuard = [](std::string_view data_,size_t offset_) -> size_t
609+
static constexpr auto endOfGuard = [](std::string_view data_,size_t offset_) -> size_t
600610
{
601611
return endOfFuncLike(data_,offset_,false);
602612
};
@@ -1854,13 +1864,13 @@ void Markdown::Private::processInline(std::string_view data)
18541864
while (i<size)
18551865
{
18561866
// skip over characters that do not trigger a specific action
1857-
while (end<size && ((action=actions[static_cast<uint8_t>(data[end])])==nullptr)) end++;
1867+
while (end<size && ((action=Markdown::actions[static_cast<uint8_t>(data[end])])==nullptr)) end++;
18581868
// and add them to the output
18591869
out+=data.substr(i,end-i);
18601870
if (end>=size) break;
18611871
i=end;
18621872
// do the action matching a special character at i
1863-
int iend = action(data.substr(i),i);
1873+
int iend = action(*this,data.substr(i),i);
18641874
if (iend<=0) // update end
18651875
{
18661876
end=i+1-iend;
@@ -2562,7 +2572,7 @@ size_t Markdown::Private::writeTableBlock(std::string_view data)
25622572
size_t cc = 0;
25632573
size_t ret = findTableColumns(data.substr(i),start,end,cc);
25642574
size_t k=0;
2565-
std::vector<int> columnAlignment(columns);
2575+
std::vector<Alignment> columnAlignment(columns);
25662576

25672577
bool leftMarker=false, rightMarker=false, startFound=false;
25682578
size_t j=start+i;
@@ -2706,10 +2716,10 @@ size_t Markdown::Private::writeTableBlock(std::string_view data)
27062716
// use appropriate alignment style
27072717
switch (columnAlignment[c])
27082718
{
2709-
case AlignLeft: out+="Left\""; break;
2710-
case AlignRight: out+="Right\""; break;
2711-
case AlignCenter: out+="Center\""; break;
2712-
case AlignNone: out+="None\""; break;
2719+
case Alignment::Left: out+="Left\""; break;
2720+
case Alignment::Right: out+="Right\""; break;
2721+
case Alignment::Center: out+="Center\""; break;
2722+
case Alignment::None: out+="None\""; break;
27132723
}
27142724

27152725
if (rowSpan > 1)

src/markdown.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class Markdown
4141
private:
4242
struct Private;
4343
std::unique_ptr<Private> prv;
44+
using Action_t = std::function<int(Private&,std::string_view,size_t)>;
45+
using ActionTable_t = std::array<Action_t,256>;
46+
static ActionTable_t fill_table();
47+
static ActionTable_t actions;
4448
};
4549

4650
class MarkdownOutlineParser : public OutlineParserInterface

0 commit comments

Comments
 (0)