summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/context.cxx299
-rw-r--r--cli/context.hxx67
-rw-r--r--cli/generator.cxx101
-rw-r--r--cli/html.cxx26
-rw-r--r--cli/man.cxx6
-rw-r--r--cli/source.cxx8
-rw-r--r--cli/txt.cxx5
-rw-r--r--tests/toc/toc.cli58
-rw-r--r--tests/toc/toc.html82
9 files changed, 573 insertions, 79 deletions
diff --git a/cli/context.cxx b/cli/context.cxx
index 9ba20ab..ce58779 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -98,12 +98,14 @@ namespace
context::
context (ostream& os_,
+ output_type ot_,
semantics::cli_unit& unit_,
options_type const& ops)
: data_ (new (shared) data),
os (os_),
unit (unit_),
options (ops),
+ ot (ot_),
modifier (options.generate_modifier ()),
specifier (options.generate_specifier ()),
inl (data_->inl_),
@@ -112,7 +114,9 @@ context (ostream& os_,
cli (data_->cli_),
reserved_name_map (options.reserved_name ()),
keyword_set (data_->keyword_set_),
- link_regex (data_->link_regex_)
+ link_regex (data_->link_regex_),
+ toc (data_->toc_),
+ tocs (data_->tocs_)
{
if (options.suppress_usage ())
usage = ut_none;
@@ -150,6 +154,8 @@ context (ostream& os_,
throw generation_failed ();
}
}
+
+ toc = 0;
}
context::
@@ -158,6 +164,7 @@ context (context& c)
os (c.os),
unit (c.unit),
options (c.options),
+ ot (c.ot),
modifier (c.modifier),
specifier (c.specifier),
usage (c.usage),
@@ -167,7 +174,9 @@ context (context& c)
cli (c.cli),
reserved_name_map (c.reserved_name_map),
keyword_set (c.keyword_set),
- link_regex (c.link_regex)
+ link_regex (c.link_regex),
+ toc (c.toc),
+ tocs (c.tocs)
{
}
@@ -1120,7 +1129,7 @@ html_margin (string& v)
string context::
-format (semantics::scope& scope, output_type ot, string const& s, bool para)
+format (semantics::scope& scope, string const& s, bool para)
{
stack<block> blocks;
blocks.push (block (block::text, para)); // Top-level.
@@ -1165,15 +1174,61 @@ format (semantics::scope& scope, output_type ot, string const& s, bool para)
l = s.c_str () + b;
n = (last ? s.size () : e) - b;
- // Perform variable expansions (\$var$).
+ // Perform variable expansions (\$var$). Also detect the switch
+ // to/from TOC mode.
//
+ unsigned short t (toc);
if (substitute (scope, l, n, subst))
{
+ if (subst.empty ())
+ continue;
+
+ if (t != toc)
+ {
+ // This is a TOC prologue/epilogue (returned by start/end_toc()) and
+ // we shouldn't be formatting it.
+ //
+ assert (blocks.size () == 1);
+ string& v (blocks.top ().value);
+
+ // Require that \$TOC$ appears in its own doc string. Failed this
+ // it is tricky to get indentation right.
+ //
+ if (!v.empty () || !last)
+ {
+ cerr << "error: TOC variable should be in its own documentation "
+ << "string" << endl;
+ throw generation_failed ();
+ }
+
+ switch (ot)
+ {
+ case ot_plain: break;
+ case ot_html:
+ {
+ // Different "newline protocol" inside TOC.
+ //
+ v += subst;
+
+ if (toc)
+ v += '\n';
+ }
+ case ot_man: break;
+ }
+
+ continue;
+ }
+
l = subst.c_str ();
n = subst.size ();
}
}
+ // If this is TOC phase 2, then we simply ignore everything.
+ //
+ if (toc == 2)
+ continue;
+
const char* ol (l); // Original, full line for diagnostics.
size_t on (n);
@@ -1412,8 +1467,13 @@ format (semantics::scope& scope, output_type ot, string const& s, bool para)
case block::pre: break; // No push.
}
- // Output paragraph text.
+ // Output paragraph text. If we are in TOC mode and this is a top-level
+ // block, then pretend we don't have anything to write. For non-top-level
+ // blocks, we handle this below, when we pop them.
//
+ if (toc && blocks.size () == 1)
+ n = 0;
+
if (n != 0)
{
block& b (blocks.top ());
@@ -1557,6 +1617,135 @@ format (semantics::scope& scope, output_type ot, string const& s, bool para)
block& b (blocks.top ());
string& v (b.value);
+ // Handle poping into top-level block in TOC mode.
+ //
+ if (toc && blocks.size () == 1)
+ {
+ if (pb.kind == block::h)
+ {
+ switch (ot)
+ {
+ case ot_plain: break;
+ case ot_html:
+ {
+ char t (ph[0]);
+
+ // Unwind heading levels that are deeper ("more sub") than us.
+ //
+ for (; tocs.size () != 1; tocs.pop_back ())
+ {
+ toc_entry const& e (tocs.back ());
+
+ bool pop (true);
+
+ switch (t)
+ {
+ case '0':
+ case 'H':
+ case '1': break; // Always unwind.
+ case 'h':
+ {
+ pop = html_h[1] == '1' || e.type == 'h' || e.type == '2';
+ break;
+ }
+ case '2': pop = e.type == '2'; break;
+ }
+
+ if (!pop)
+ break;
+
+ // If we have sub-headings, then we need to close the table.
+ //
+ if (e.count != 0)
+ {
+ size_t l (tocs.size ());
+
+ v += string (l * 4 - 2, ' ') + "</table>\n";
+ v += string (l * 4 - 4, ' ') + "</td></tr>\n";
+ }
+ else
+ // Otherwise it is inline.
+ //
+ v += "</td></tr>\n";
+ }
+
+ size_t l (tocs.size ());
+ toc_entry& e (tocs.back ());
+
+ // If this is a first sub-entry, then we need to open the
+ // sub-table.
+ //
+ string in ((l * 4) - 2, ' ');
+
+ if (l > 1 && e.count == 0)
+ {
+ v += "\n";
+ v += in + "<table class=\"toc\">\n";
+ }
+
+ in += " ";
+
+ switch (t)
+ {
+ case 'H':
+ {
+ v += in + "<tr><th colspan=\"2\">" + pv + "</th></tr>\n";
+ break;
+ }
+ case '0':
+ case '1':
+ case 'h':
+ case '2':
+ {
+ // Calculate Chapter(X)/Section(X.Y)/Subsection(X.Y.Z) unless
+ // it is the preface (or a subsection thereof).
+ //
+ string n;
+ if (t != '0')
+ {
+ ++e.count;
+
+ for (toc_stack::const_iterator i (tocs.begin ());
+ i != tocs.end ();
+ ++i)
+ {
+ if (i->type == '0')
+ {
+ n.clear ();
+ break;
+ }
+
+ if (!n.empty ())
+ n += '.';
+
+ ostringstream os;
+ os << i->count;
+ n += os.str ();
+ }
+ }
+
+ v += in + "<tr><th>" + n + "</th><td>" + pv; // No newline
+ tocs.push_back (toc_entry (t));
+ break;
+ }
+ }
+
+ // Same as in non-TOC mode below.
+ //
+ // @@ This only works for a single string fragment.
+ //
+ if (ph[0] == '0' || ph[0] == '1')
+ html_h = "h2";
+
+ break;
+ }
+ case ot_man: break;
+ }
+ }
+
+ continue;
+ }
+
switch (ot)
{
case ot_plain:
@@ -1752,7 +1941,61 @@ format (semantics::scope& scope, output_type ot, string const& s, bool para)
}
string context::
-substitute (const string& s, semantics::cli_unit& u, const path* d)
+start_toc ()
+{
+ switch (ot)
+ {
+ case ot_plain: break;
+ case ot_html:
+ {
+ tocs.push_back (toc_entry ('\0'));
+ return " <table class=\"toc\">";
+ }
+ case ot_man: break;
+ }
+}
+
+string context::
+end_toc ()
+{
+ switch (ot)
+ {
+ case ot_plain: break;
+ case ot_html:
+ {
+ string v;
+
+ // Unwind the TOC stack until we reach top level. Same code as in
+ // format().
+ //
+ for (; tocs.size () != 1; tocs.pop_back ())
+ {
+ toc_entry const& e (tocs.back ());
+
+ // If we have sub-headings, then we need to close the table.
+ //
+ if (e.count != 0)
+ {
+ size_t l (tocs.size ());
+
+ v += string (l * 4 - 2, ' ') + "</table>\n";
+ v += string (l * 4 - 4, ' ') + "</td></tr>\n";
+ }
+ else
+ // Otherwise it is inline.
+ //
+ v += "</td></tr>\n";
+ }
+
+ v += " </table>";
+ return v;
+ }
+ case ot_man: break;
+ }
+}
+
+string context::
+substitute (const string& s, const path* d)
{
string r;
@@ -1832,9 +2075,31 @@ substitute (const string& s, semantics::cli_unit& u, const path* d)
}
else
{
+ // Handle special variables.
+ //
+ if (v == "TOC")
+ {
+ if (!r.empty () || p + 1 != n)
+ {
+ cerr << "error: TOC variable should be on its own line" << endl;
+ throw generation_failed ();
+ }
+
+ // Invert the TOC mode.
+ //
+ if ((toc = toc ? 0 : 1))
+ r = start_toc ();
+ else
+ r = end_toc ();
+
+ return r;
+ }
+
// Lookup and substiute the variable.
//
- if (semantics::doc* d = u.lookup<semantics::doc> ("", "var: " + v))
+ using semantics::doc;
+
+ if (doc* d = unit.lookup<doc> ("", "var: " + v))
r += d->front ();
else
{
@@ -1900,6 +2165,26 @@ substitute (semantics::scope& scope, const char* s, size_t n, string& result)
++e;
string v (s, e, p - e);
+ // Handle special variables.
+ //
+ if (v == "TOC")
+ {
+ if (!result.empty () || p + 1 != n)
+ {
+ cerr << "error: TOC variable should be its own paragraph" << endl;
+ throw generation_failed ();
+ }
+
+ // Invert the TOC mode.
+ //
+ if ((toc = toc ? 0 : 1))
+ result = start_toc ();
+ else
+ result = end_toc ();
+
+ return true;
+ }
+
// Lookup and substiute.
//
using semantics::doc;
diff --git a/cli/context.hxx b/cli/context.hxx
index 9f10a00..79c9aab 100644
--- a/cli/context.hxx
+++ b/cli/context.hxx
@@ -71,6 +71,17 @@ public:
semantics::cli_unit& unit;
options_type const& options;
+ // Documentation output type.
+ //
+ enum output_type
+ {
+ ot_plain,
+ ot_html,
+ ot_man
+ };
+
+ output_type ot;
+
bool modifier;
bool specifier;
usage_type usage;
@@ -88,14 +99,35 @@ public:
regex_mapping const& link_regex;
+ // TOC phase.
+ //
+ // 0 - non-TOC
+ // 1 - generating TOC after seeing expansion but before restart
+ // 2 - generating TOC after restart
+ // 0 - non-TOC after seeing expansion after restart
+ //
+ unsigned short& toc;
+
+ struct toc_entry
+ {
+ toc_entry (char t = '\0', size_t c = 0): type (t), count (c) {}
+
+ char type; // Entry type (output type-specific, usually X from \hX).
+ size_t count; // Number of sub-entries so far.
+ };
+
+ typedef std::vector<toc_entry> toc_stack;
+ toc_stack& tocs;
+
private:
struct data
{
string inl_;
string cli_;
keyword_set_type keyword_set_;
-
regex_mapping link_regex_;
+ unsigned short toc_;
+ toc_stack tocs_;
};
public:
@@ -111,13 +143,6 @@ public:
// the <arg>-style constructs to \i{arg}. Format converts the string
// to the output format.
//
- enum output_type
- {
- ot_plain,
- ot_html,
- ot_man
- };
-
static string
translate_arg (string const&, std::set<string>&);
@@ -127,24 +152,27 @@ public:
// If para is true, start a new paragraph.
//
string
- format (semantics::scope&, output_type, string const&, bool para);
+ format (semantics::scope&, string const&, bool para);
void
format_line (output_type, string&, const char*, size_t);
+ // Called when we switch to the TOC mode and when we exit it,
+ // respectively.
+ //
+ string
+ start_toc ();
+
+ string
+ end_toc ();
+
// Substitute doc variable expansions ($var$). Var must be a C identifier.
// If the path is not NULL, then also recognize names that start with either
// ./ or ../ and treat them as files relative to path. Such file expansions
- // are substituted with the files' contents.
+ // are substituted with the file contents.
//
- static string
- substitute (const string&, semantics::cli_unit&, const path* = 0);
-
string
- substitute (const string& s, const path* p = 0)
- {
- return substitute (s, unit, p);
- }
+ substitute (const string&, const path* = 0);
// Substitute doc variable expansions (\$var$). Note that it leaves escapes
// (\\$) as is. Return true if any substitutions have been made, in which
@@ -204,7 +232,10 @@ public:
first_sentence (string const&);
public:
- context (std::ostream&, semantics::cli_unit&, options_type const&);
+ context (std::ostream&,
+ output_type,
+ semantics::cli_unit&,
+ options_type const&);
context (context&);
diff --git a/cli/generator.cxx b/cli/generator.cxx
index 5964c25..cbb3ec7 100644
--- a/cli/generator.cxx
+++ b/cli/generator.cxx
@@ -80,14 +80,32 @@ namespace
}
void
- append (ostream& os,
- vector<string> const& text,
- string const& file,
- semantics::cli_unit& u)
+ append (context& ctx, string const& s, const path* d = 0)
+ {
+ // Detect the switch to/from TOC mode.
+ //
+ unsigned short t (ctx.toc);
+ string const& r (ctx.substitute (s, d));
+
+ if (t != ctx.toc)
+ {
+ if (!r.empty ()) // TOC prologue/epilogue (returned by start/end_toc()).
+ ctx.os << r << endl;
+ }
+ // Skip it if we are in the TOC mode.
+ //
+ else if (!t)
+ ctx.os << r << endl;
+ }
+
+ void
+ append (context& ctx, vector<string> const& text, string const& file)
{
for (vector<string>::const_iterator i (text.begin ());
i != text.end (); ++i)
- os << context::substitute (*i, u) << endl;
+ {
+ append (ctx, *i);
+ }
if (!file.empty ())
{
@@ -101,7 +119,7 @@ namespace
// the delimiter.
//
for (string s; getline (ifs, s); )
- os << context::substitute (s, u, &d) << endl;
+ append (ctx, s, &d);
}
}
}
@@ -176,7 +194,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// Process names.
//
{
- context ctx (cerr, unit, ops);
+ context ctx (cerr, context::ot_plain, unit, ops);
process_names (ctx);
}
@@ -265,7 +283,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// HXX
//
{
- context ctx (hxx, unit, ops);
+ context ctx (hxx, context::ot_plain, unit, ops);
string guard (make_guard (gp + hxx_name, ctx));
@@ -277,7 +295,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
//
hxx << "// Begin prologue." << endl
<< "//" << endl;
- append (hxx, ops.hxx_prologue (), ops.hxx_prologue_file (), unit);
+ append (ctx, ops.hxx_prologue (), ops.hxx_prologue_file ());
hxx << "//" << endl
<< "// End prologue." << endl
<< endl;
@@ -304,7 +322,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
//
hxx << "// Begin epilogue." << endl
<< "//" << endl;
- append (hxx, ops.hxx_epilogue (), ops.hxx_epilogue_file (), unit);
+ append (ctx, ops.hxx_epilogue (), ops.hxx_epilogue_file ());
hxx << "//" << endl
<< "// End epilogue." << endl
<< endl;
@@ -316,13 +334,13 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
//
if (inl)
{
- context ctx (ixx, unit, ops);
+ context ctx (ixx, context::ot_plain, unit, ops);
// Copy prologue.
//
ixx << "// Begin prologue." << endl
<< "//" << endl;
- append (ixx, ops.ixx_prologue (), ops.ixx_prologue_file (), unit);
+ append (ctx, ops.ixx_prologue (), ops.ixx_prologue_file ());
ixx << "//" << endl
<< "// End prologue." << endl
<< endl;
@@ -342,7 +360,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
//
ixx << "// Begin epilogue." << endl
<< "//" << endl;
- append (ixx, ops.ixx_epilogue (), ops.ixx_epilogue_file (), unit);
+ append (ctx, ops.ixx_epilogue (), ops.ixx_epilogue_file ());
ixx << "//" << endl
<< "// End epilogue." << endl;
}
@@ -350,13 +368,13 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// CXX
//
{
- context ctx (cxx, unit, ops);
+ context ctx (cxx, context::ot_plain, unit, ops);
// Copy prologue.
//
cxx << "// Begin prologue." << endl
<< "//" << endl;
- append (cxx, ops.cxx_prologue (), ops.cxx_prologue_file (), unit);
+ append (ctx, ops.cxx_prologue (), ops.cxx_prologue_file ());
cxx << "//" << endl
<< "// End prologue." << endl
<< endl;
@@ -385,7 +403,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
//
cxx << "// Begin epilogue." << endl
<< "//" << endl;
- append (cxx, ops.cxx_epilogue (), ops.cxx_epilogue_file (), unit);
+ append (ctx, ops.cxx_epilogue (), ops.cxx_epilogue_file ());
cxx << "//" << endl
<< "// End epilogue." << endl
<< endl;
@@ -420,13 +438,20 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// The explicit cast helps VC++ 8.0 overcome its issues.
//
ostream& os (ops.stdout_ () ? cout : static_cast<ostream&> (man));
+ context ctx (os, context::ot_man, unit, ops);
- append (os, ops.man_prologue (), ops.man_prologue_file (), unit);
-
- context ctx (os, unit, ops);
- generate_man (ctx);
+ for (bool first (true); first || ctx.toc; first = false)
+ {
+ append (ctx, ops.man_prologue (), ops.man_prologue_file ());
+ generate_man (ctx);
+ append (ctx, ops.man_epilogue (), ops.man_epilogue_file ());
- append (os, ops.man_epilogue (), ops.man_epilogue_file (), unit);
+ if (ctx.toc)
+ {
+ assert (first); // Second run should end in non-TOC mode.
+ ctx.toc++; // TOC phase after restart.
+ }
+ }
}
// HTML output
@@ -460,13 +485,20 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// The explicit cast helps VC++ 8.0 overcome its issues.
//
ostream& os (ops.stdout_ () ? cout : static_cast<ostream&> (html));
+ context ctx (os, context::ot_html, unit, ops);
- append (os, ops.html_prologue (), ops.html_prologue_file (), unit);
-
- context ctx (os, unit, ops);
- generate_html (ctx);
+ for (bool first (true); first || ctx.toc; first = false)
+ {
+ append (ctx, ops.html_prologue (), ops.html_prologue_file ());
+ generate_html (ctx);
+ append (ctx, ops.html_epilogue (), ops.html_epilogue_file ());
- append (os, ops.html_epilogue (), ops.html_epilogue_file (), unit);
+ if (ctx.toc)
+ {
+ assert (first); // Second run should end in non-TOC mode.
+ ctx.toc++; // TOC phase after restart.
+ }
+ }
}
// txt output
@@ -497,13 +529,20 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p)
// The explicit cast helps VC++ 8.0 overcome its issues.
//
ostream& os (ops.stdout_ () ? cout : static_cast<ostream&> (txt));
+ context ctx (os, context::ot_plain, unit, ops);
- append (os, ops.txt_prologue (), ops.txt_prologue_file (), unit);
-
- context ctx (os, unit, ops);
- generate_txt (ctx);
+ for (bool first (true); first || ctx.toc; first = false)
+ {
+ append (ctx, ops.txt_prologue (), ops.txt_prologue_file ());
+ generate_txt (ctx);
+ append (ctx, ops.txt_epilogue (), ops.txt_epilogue_file ());
- append (os, ops.txt_epilogue (), ops.txt_epilogue_file (), unit);
+ if (ctx.toc)
+ {
+ assert (first); // Second run should end in non-TOC mode.
+ ctx.toc++; // TOC phase after restart.
+ }
+ }
}
auto_rm.cancel ();
diff --git a/cli/html.cxx b/cli/html.cxx
index da94a65..2d018e0 100644
--- a/cli/html.cxx
+++ b/cli/html.cxx
@@ -139,10 +139,10 @@ namespace
if (n > 1)
translate_arg (ds[0], arg_set);
- string s (format (ds.scope (),
- ot_html,
- escape_html (translate (d, arg_set)),
- true));
+ unsigned short t (toc); // Detect the switch to/from TOC mode.
+
+ string s (
+ format (ds.scope (), escape_html (translate (d, arg_set)), true));
if (s.empty ())
return;
@@ -154,9 +154,11 @@ namespace
list_ = false;
}
- wrap_lines (os, s, 2);
- os << endl
- << endl;
+ wrap_lines (os, s, (t || toc) ? 0 : 2); // TOC mode does its own thing.
+
+ if (!toc) // TOC mode does its own thing.
+ os << endl
+ << endl;
}
private:
@@ -179,6 +181,9 @@ namespace
if (options.suppress_undocumented () && doc.empty ())
return;
+ if (toc)
+ return; // No option documentation in the TOC mode.
+
if (!list_)
{
os << " <dl class=\"options\">" << endl;
@@ -211,7 +216,7 @@ namespace
translate_arg (
doc.size () > 0 ? doc[0] : string ("<arg>"), arg_set));
- os << ' ' << format (o.scope (), ot_html, escape_html (s), false);
+ os << ' ' << format (o.scope (), escape_html (s), false);
}
os << "</dt>" << endl;
@@ -234,10 +239,7 @@ namespace
// Format the documentation string.
//
- d = format (o.scope (),
- ot_html,
- escape_html (translate (d, arg_set)),
- false);
+ d = format (o.scope (), escape_html (translate (d, arg_set)), false);
wrap_lines (os, "<dd>" + d + "</dd>", 4);
os << endl;
diff --git a/cli/man.cxx b/cli/man.cxx
index 7e2757c..e55bc17 100644
--- a/cli/man.cxx
+++ b/cli/man.cxx
@@ -94,7 +94,7 @@ namespace
if (n > 1)
translate_arg (ds[0], arg_set);
- string s (format (ds.scope (), ot_man, translate (d, arg_set), true));
+ string s (format (ds.scope (), translate (d, arg_set), true));
if (s.empty ())
return;
@@ -145,7 +145,7 @@ namespace
translate_arg (
doc.size () > 0 ? doc[0] : string ("<arg>"), arg_set));
- os << ' ' << format (o.scope (), ot_man, s, false);
+ os << ' ' << format (o.scope (), s, false);
}
os << "\"" << endl;
@@ -168,7 +168,7 @@ namespace
// Format the documentation string.
//
- d = format (o.scope (), ot_man, translate (d, arg_set), false);
+ d = format (o.scope (), translate (d, arg_set), false);
wrap_lines (os, d);
os << endl;
diff --git a/cli/source.cxx b/cli/source.cxx
index 14a6a9a..57f5922 100644
--- a/cli/source.cxx
+++ b/cli/source.cxx
@@ -260,7 +260,7 @@ namespace
if (n > 1 && options.ansi_color ())
translate_arg (ds[0], arg_set);
- d = format (ds.scope (), ot_plain, translate (d, arg_set), true);
+ d = format (ds.scope (), translate (d, arg_set), true);
if (d.empty ())
return;
@@ -331,7 +331,7 @@ namespace
s = translate_arg (s, arg_set);
}
- l += txt_size (format (o.scope (), ot_plain, s, false));
+ l += txt_size (format (o.scope (), s, false));
}
if (l > length_)
@@ -422,7 +422,7 @@ namespace
if (color)
s = translate_arg (s, arg_set);
- s = format (o.scope (), ot_plain, s, false);
+ s = format (o.scope (), s, false);
os << escape_str (s);
l += txt_size (s);
@@ -458,7 +458,7 @@ namespace
if (color)
d = translate (d, arg_set);
- d = format (o.scope (), ot_plain, d, false);
+ d = format (o.scope (), d, false);
if (!d.empty ())
wrap_lines (os, d, length_ + 1, l); // +1 for extra space after arg.
diff --git a/cli/txt.cxx b/cli/txt.cxx
index ccce8ef..388ae0f 100644
--- a/cli/txt.cxx
+++ b/cli/txt.cxx
@@ -156,10 +156,7 @@ namespace
if (n > 1 && options.ansi_color ())
translate_arg (ds[0], arg_set);
- string s (format (ds.scope (),
- ot_plain,
- translate (d, arg_set),
- true));
+ string s (format (ds.scope (), translate (d, arg_set), true));
if (s.empty ())
return;
diff --git a/tests/toc/toc.cli b/tests/toc/toc.cli
new file mode 100644
index 0000000..5e9c43a
--- /dev/null
+++ b/tests/toc/toc.cli
@@ -0,0 +1,58 @@
+"\h1|Table of Contents|"
+"\$TOC$"
+
+"
+\h0|Preface|
+
+This document describes something awesome.
+
+\h|About This Document|
+
+And this document is also awesome.
+
+\h|More Information|
+
+It is so awesome that no further information will be required."
+
+"
+\H|PART I|
+
+Start of part one.
+
+\h1|Introduction|
+
+Beginning of the first chapter.
+
+\h|Architecture and Workflow|
+
+Some basics.
+
+\h|Benefits|
+
+You will like them.
+
+\h1|Hello World|
+
+Beginning of the second chapter.
+
+\h|Setup|
+
+More basics.
+
+\h|Compiling|
+
+How to build the example
+
+\h2|Compiling with GCC|
+
+GCC
+
+\h2|Compiling with Clang|
+
+Clang
+
+\h|Conclusion|
+
+Some remarks.
+
+"
diff --git a/tests/toc/toc.html b/tests/toc/toc.html
new file mode 100644
index 0000000..383ff12
--- /dev/null
+++ b/tests/toc/toc.html
@@ -0,0 +1,82 @@
+ <h1>Table of Contents</h1>
+
+ <table class="toc">
+ <tr><th></th><td>Preface
+ <table class="toc">
+ <tr><th></th><td>About This Document</td></tr>
+ <tr><th></th><td>More Information</td></tr>
+ </table>
+ </td></tr>
+ <tr><th colspan="2">PART I</th></tr>
+ <tr><th>1</th><td>Introduction
+ <table class="toc">
+ <tr><th>1.1</th><td>Architecture and Workflow</td></tr>
+ <tr><th>1.2</th><td>Benefits</td></tr>
+ </table>
+ </td></tr>
+ <tr><th>2</th><td>Hello World
+ <table class="toc">
+ <tr><th>2.1</th><td>Setup</td></tr>
+ <tr><th>2.2</th><td>Compiling
+ <table class="toc">
+ <tr><th>2.2.1</th><td>Compiling with GCC</td></tr>
+ <tr><th>2.2.2</th><td>Compiling with Clang</td></tr>
+ </table>
+ </td></tr>
+ <tr><th>2.3</th><td>Conclusion</td></tr>
+ </table>
+ </td></tr>
+ </table>
+
+ <h1 class="preface">Preface</h1>
+
+ <p>This document describes something awesome.</p>
+
+ <h2>About This Document</h2>
+
+ <p>And this document is also awesome.</p>
+
+ <h2>More Information</h2>
+
+ <p>It is so awesome that no further information will be required.</p>
+
+ <h1 class="part">PART I</h1>
+
+ <p>Start of part one.</p>
+
+ <h1>Introduction</h1>
+
+ <p>Beginning of the first chapter.</p>
+
+ <h2>Architecture and Workflow</h2>
+
+ <p>Some basics.</p>
+
+ <h2>Benefits</h2>
+
+ <p>You will like them.</p>
+
+ <h1>Hello World</h1>
+
+ <p>Beginning of the second chapter.</p>
+
+ <h2>Setup</h2>
+
+ <p>More basics.</p>
+
+ <h2>Compiling</h2>
+
+ <p>How to build the example</p>
+
+ <h3>Compiling with GCC</h3>
+
+ <p>GCC</p>
+
+ <h3>Compiling with Clang</h3>
+
+ <p>Clang</p>
+
+ <h2>Conclusion</h2>
+
+ <p>Some remarks.</p>
+