Skip to content

Commit bf60a45

Browse files
committed
chore: marginally better adoc escaping
1 parent a54d4a5 commit bf60a45

File tree

3 files changed

+78
-35
lines changed

3 files changed

+78
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{{#if members}}
22
== {{title}}
3-
[,cols=2]
3+
[cols=2,separator=¦]
44
|===
5-
|Name |Description
5+
¦Name ¦Description
66
{{#each (sort_by members "name")}}
77
{{>info-member .}}
88
{{/each}}
99
|===
10-
{{/if}}
10+
{{/if}}

share/mrdocs/addons/generator/asciidoc/partials/info-member.adoc.hbs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
{{!-- |xref:{{ref}}[`pass:v[{{name}}]`] | --}}
2-
|xref:{{ref}}[`pass:v[{{>declarator-id . nolink=true}}]`] |
1+
¦xref:{{ref}}[`{{>declarator-id . nolink=true}}`] ¦
32
{{#if (ne kind "overload")~}}
43
{{~doc.brief}}
54
{{else~}}

src/lib/Gen/adoc/AdocCorpus.cpp

+74-30
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,65 @@ namespace adoc {
2424

2525
namespace {
2626

27+
std::string
28+
escapeAdoc(
29+
std::string_view str)
30+
{
31+
std::string result;
32+
result.reserve(str.size());
33+
for(char ch : str)
34+
{
35+
switch(ch)
36+
{
37+
case '&':
38+
result.append("&");
39+
break;
40+
case '<':
41+
result.append("&lt;");
42+
break;
43+
case '>':
44+
result.append("&gt;");
45+
break;
46+
case '[':
47+
result.append("&lsqb;");
48+
break;
49+
case ']':
50+
result.append("&rsqb;");
51+
break;
52+
case '|':
53+
result.append("&vert;");
54+
break;
55+
case '=':
56+
result.append("&equals;");
57+
break;
58+
case '/':
59+
result.append("&sol;");
60+
break;
61+
default:
62+
result.push_back(ch);
63+
break;
64+
}
65+
}
66+
return result;
67+
}
68+
2769
class DocVisitor
2870
{
2971
const AdocCorpus& corpus_;
3072
std::string& dest_;
3173
std::back_insert_iterator<std::string> ins_;
3274

75+
template<typename Fn>
76+
bool
77+
write(
78+
const doc::Node& node,
79+
Fn&& fn)
80+
{
81+
const auto n_before = dest_.size();
82+
doc::visit(node, std::forward<Fn>(fn));
83+
return dest_.size() != n_before;
84+
}
85+
3386
public:
3487
DocVisitor(
3588
const AdocCorpus& corpus,
@@ -126,7 +179,7 @@ DocVisitor::
126179
operator()(
127180
doc::Heading const& I)
128181
{
129-
fmt::format_to(ins_, "\n=== {}\n", I.string);
182+
fmt::format_to(ins_, "\n=== {}\n", escapeAdoc(I.string));
130183
}
131184

132185
// Also handles doc::Brief
@@ -135,22 +188,18 @@ DocVisitor::
135188
operator()(
136189
doc::Paragraph const& I)
137190
{
138-
for(auto const& it : RangeFor(I.children))
191+
std::span children = I.children;
192+
if(children.empty())
193+
return;
194+
dest_.append("\n");
195+
bool non_empty = write(*children.front(), *this);
196+
for(auto const& child : children.subspan(1))
139197
{
140-
auto const n = dest_.size();
141-
doc::visit(*it.value, *this);
142-
// detect empty text blocks
143-
if(! it.last && dest_.size() > n)
144-
{
145-
// wrap past 80 cols
146-
if(dest_.size() < 80)
147-
dest_.push_back(' ');
148-
else
149-
dest_.append("\n");
150-
}
198+
if(non_empty)
199+
dest_.push_back(' ');
200+
non_empty = write(*child, *this);
151201
}
152202
dest_.push_back('\n');
153-
// dest_.push_back('\n');
154203
}
155204

156205
void
@@ -161,7 +210,7 @@ operator()(
161210
dest_.append("link:");
162211
dest_.append(I.href);
163212
dest_.push_back('[');
164-
dest_.append(I.string);
213+
dest_.append(escapeAdoc(I.string));
165214
dest_.push_back(']');
166215
}
167216

@@ -170,20 +219,16 @@ DocVisitor::
170219
operator()(
171220
doc::ListItem const& I)
172221
{
222+
std::span children = I.children;
223+
if(children.empty())
224+
return;
173225
dest_.append("\n* ");
174-
for(auto const& it : RangeFor(I.children))
226+
bool non_empty = write(*children.front(), *this);
227+
for(auto const& child : children.subspan(1))
175228
{
176-
auto const n = dest_.size();
177-
doc::visit(*it.value, *this);
178-
// detect empty text blocks
179-
if(! it.last && dest_.size() > n)
180-
{
181-
// wrap past 80 cols
182-
if(dest_.size() < 80)
183-
dest_.push_back(' ');
184-
else
185-
dest_.append("\n");
186-
}
229+
if(non_empty)
230+
dest_.push_back(' ');
231+
non_empty = write(*child, *this);
187232
}
188233
dest_.push_back('\n');
189234
}
@@ -220,7 +265,7 @@ operator()(doc::Text const& I)
220265
// Asciidoc text must not have leading
221266
// else they can be rendered up as code.
222267
std::string_view s = trim(I.string);
223-
fmt::format_to(std::back_inserter(dest_), "pass:v,q[{}]", s);
268+
dest_.append(escapeAdoc(s));
224269
}
225270

226271
void
@@ -253,11 +298,10 @@ void
253298
DocVisitor::
254299
operator()(doc::Reference const& I)
255300
{
256-
//dest_ += I.string;
257301
if(I.id == SymbolID::invalid)
258302
return (*this)(static_cast<const doc::Text&>(I));
259303
fmt::format_to(std::back_inserter(dest_), "xref:{}[{}]",
260-
corpus_.getXref(corpus_->get(I.id)), I.string);
304+
corpus_.getXref(corpus_->get(I.id)), escapeAdoc(I.string));
261305
}
262306

263307
std::size_t

0 commit comments

Comments
 (0)