summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-02-01 12:08:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-02-01 12:08:06 +0200
commita22e3dc68dd88eb047bfd9716e5cb780c95a3cea (patch)
treee991ee32b6155ed262cbcb32b6202907bf4163b1
parentde673d0b39bff8d8da3d3818de7c79bf0143eb2c (diff)
Add support for link transformation (--link-regex)
-rw-r--r--cli/context.cxx152
-rw-r--r--cli/context.hxx17
-rw-r--r--cli/options.cli22
-rw-r--r--cli/options.cxx30
-rw-r--r--cli/options.hxx12
-rw-r--r--cli/options.ixx18
6 files changed, 226 insertions, 25 deletions
diff --git a/cli/context.cxx b/cli/context.cxx
index 506c8fa..1aa7833 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -111,7 +111,8 @@ context (ostream& os_,
opt_sep (options.option_separator ()),
cli (data_->cli_),
reserved_name_map (options.reserved_name ()),
- keyword_set (data_->keyword_set_)
+ keyword_set (data_->keyword_set_),
+ link_regex (data_->link_regex_)
{
if (options.suppress_usage ())
usage = ut_none;
@@ -133,6 +134,22 @@ context (ostream& os_,
for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i)
data_->keyword_set_.insert (keywords[i]);
+
+ // Link regex.
+ //
+ for (vector<string>::const_iterator i (ops.link_regex ().begin ());
+ i != ops.link_regex ().end (); ++i)
+ {
+ try
+ {
+ data_->link_regex_.push_back (regexsub (*i));
+ }
+ catch (const regex_format& e)
+ {
+ cerr << "error: invalid regex '" << *i << "': " << e.what () << endl;
+ throw generation_failed ();
+ }
+ }
}
context::
@@ -149,7 +166,8 @@ context (context& c)
opt_sep (c.opt_sep),
cli (c.cli),
reserved_name_map (c.reserved_name_map),
- keyword_set (c.keyword_set)
+ keyword_set (c.keyword_set),
+ link_regex (c.link_regex)
{
}
@@ -224,6 +242,43 @@ escape (string const& name) const
}
string context::
+process_link_target (const string& tg)
+{
+ bool t (options.link_regex_trace ());
+
+ if (t)
+ cerr << "link: '" << tg << "'" << endl;
+
+ string r;
+ bool found (false);
+
+ for (regex_mapping::const_iterator i (link_regex.begin ());
+ i != link_regex.end (); ++i)
+ {
+ if (t)
+ cerr << "try: '" << i->regex () << "' : ";
+
+ if (i->match (tg))
+ {
+ r = i->replace (tg);
+ found = true;
+
+ if (t)
+ cerr << "'" << r << "' : ";
+ }
+
+ if (t)
+ cerr << (found ? '+' : '-') << endl;
+
+ if (found)
+ break;
+ }
+
+ return found ? r : tg;
+}
+
+
+string context::
translate_arg (string const& s, std::set<string>& set)
{
string r;
@@ -713,11 +768,22 @@ format_line (output_type ot, string& r, const char* s, size_t n)
{
r += "<a href=\"";
- if (link_section.empty ())
- r += link_target;
- else
- r += link_target + options.html_suffix ();
+ // It might be useful to include the man section into the regex
+ // somehow.
+ //
+ string t (link_section.empty ()
+ ? link_target
+ : link_target + options.html_suffix ());
+
+ string pt (process_link_target (t));
+
+ if (pt.empty ())
+ {
+ cerr << "error: link '" << t << "' became empty" << endl;
+ throw generation_failed ();
+ }
+ r += pt;
r += "\">";
}
else
@@ -789,24 +855,42 @@ format_line (output_type ot, string& r, const char* s, size_t n)
{
if (b & link)
{
- if (!link_empty)
- r += " (";
+ string t (link_section.empty ()
+ ? link_target
+ : link_target + "(" + link_section + ")");
- if (link_section.empty ())
- r += link_target;
+ string pt (process_link_target (t));
+
+ if (pt.empty ())
+ {
+ if (link_empty)
+ {
+ cerr << "error: link target '" << t << "' became empty "
+ << "and link text is also empty" << endl;
+ throw generation_failed ();
+ }
+ }
else
{
- if (color)
- r += "\033[1m";
+ if (!link_empty)
+ r += " (";
- r += link_target + "(" + link_section + ")";
+ if (link_section.empty ())
+ r += pt;
+ else
+ {
+ if (color)
+ r += "\033[1m";
- if (color)
- r += "\033[0m";
- }
+ r += pt;
+
+ if (color)
+ r += "\033[0m";
+ }
- if (!link_empty)
- r += ")";
+ if (!link_empty)
+ r += ")";
+ }
}
else
{
@@ -864,16 +948,34 @@ format_line (output_type ot, string& r, const char* s, size_t n)
{
if (b & link)
{
- if (!link_empty)
- r += " (";
+ string t (link_section.empty ()
+ ? link_target
+ : link_target + "(" + link_section + ")");
- if (link_section.empty ())
- r += link_target;
+ string pt (process_link_target (t));
+
+ if (pt.empty ())
+ {
+ if (link_empty)
+ {
+ cerr << "error: link target '" << t << "' became empty "
+ << "and link text is also empty" << endl;
+ throw generation_failed ();
+ }
+ }
else
- r += "\\fB" + link_target + "(" + link_section + ")\\fP";
+ {
+ if (!link_empty)
+ r += " (";
- if (!link_empty)
- r += ")";
+ if (link_section.empty ())
+ r += pt;
+ else
+ r += "\\fB" + pt + "\\fP";
+
+ if (!link_empty)
+ r += ")";
+ }
}
else
{
diff --git a/cli/context.hxx b/cli/context.hxx
index cdc0aa5..b33bfef 100644
--- a/cli/context.hxx
+++ b/cli/context.hxx
@@ -9,9 +9,11 @@
#include <set>
#include <map>
#include <string>
+#include <vector>
#include <ostream>
#include <cstddef> // std::size_t
+#include <cutl/re.hxx>
#include <cutl/shared-ptr.hxx>
#include <cutl/fs/path.hxx>
@@ -52,6 +54,14 @@ public:
typedef ::usage usage_type;
typedef ::class_doc class_doc_type;
+ // Regex.
+ //
+ typedef cutl::re::regex regex;
+ typedef cutl::re::regexsub regexsub;
+ typedef cutl::re::format regex_format;
+
+ typedef std::vector<regexsub> regex_mapping;
+
private:
struct data;
cutl::shared_ptr<data> data_;
@@ -76,12 +86,16 @@ public:
typedef std::set<string> keyword_set_type;
keyword_set_type const& keyword_set;
+ regex_mapping const& link_regex;
+
private:
struct data
{
string inl_;
string cli_;
keyword_set_type keyword_set_;
+
+ regex_mapping link_regex_;
};
public:
@@ -90,6 +104,9 @@ public:
string
escape (string const&) const;
+ string
+ process_link_target (const string&);
+
// Translate and format the documentation string. Translate converts
// the <arg>-style constructs to \i{arg}. Format converts the string
// to the output format.
diff --git a/cli/options.cli b/cli/options.cli
index 26bf834..8a4a3e0 100644
--- a/cli/options.cli
+++ b/cli/options.cli
@@ -234,6 +234,28 @@ class options
\c{\"\\<name>=<val>\"} syntax."
};
+ std::vector<std::string> --link-regex
+ {
+ "<regex>",
+ "Add <regex> to the list of regular expressions used to transform link
+ targets in the generated documentation. The argument to this option
+ is a Perl-like regular expression in the form
+ \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}. Any character can be
+ used as a delimiter instead of '\cb{/}' and the delimiter can be escaped
+ inside \ci{pattern} and \ci{replacement} with a backslash (\cb{\\}).
+ You can specify multiple regular expressions by repeating this option.
+ All the regular expressions are tried in the order specified and the
+ first expression that matches is used. Use the \cb{--link-regex-trace}
+ option to debug link transformation."
+ };
+
+ bool --link-regex-trace
+ {
+ "Trace the process of applying regular expressions specified with the
+ \cb{--link-regex} option. Use this option to find out why your regular
+ expressions don't do what you expected them to do."
+ };
+
// Prologues.
//
std::vector<std::string> --hxx-prologue
diff --git a/cli/options.cxx b/cli/options.cxx
index 562a789..cdc2d41 100644
--- a/cli/options.cxx
+++ b/cli/options.cxx
@@ -601,6 +601,9 @@ options ()
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -727,6 +730,9 @@ options (int& argc,
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -856,6 +862,9 @@ options (int start,
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -985,6 +994,9 @@ options (int& argc,
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -1116,6 +1128,9 @@ options (int start,
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -1243,6 +1258,9 @@ options (::cli::scanner& s,
class__specified_ (false),
docvar_ (),
docvar_specified_ (false),
+ link_regex_ (),
+ link_regex_specified_ (false),
+ link_regex_trace_ (),
hxx_prologue_ (),
hxx_prologue_specified_ (false),
ixx_prologue_ (),
@@ -1415,6 +1433,13 @@ print_usage (::std::ostream& os, ::cli::usage_para p)
os << "--docvar|-v <name>=<val> Set documentation variable <name> to the value" << ::std::endl
<< " <val>." << ::std::endl;
+ os << "--link-regex <regex> Add <regex> to the list of regular expressions" << ::std::endl
+ << " used to transform link targets in the generated" << ::std::endl
+ << " documentation." << ::std::endl;
+
+ os << "--link-regex-trace Trace the process of applying regular expressions" << ::std::endl
+ << " specified with the --link-regex option." << ::std::endl;
+
os << "--hxx-prologue <text> Insert <text> at the beginning of the generated" << ::std::endl
<< " C++ header file." << ::std::endl;
@@ -1628,6 +1653,11 @@ struct _cli_options_map_init
_cli_options_map_["-v"] =
&::cli::thunk< options, std::map<std::string, std::string>, &options::docvar_,
&options::docvar_specified_ >;
+ _cli_options_map_["--link-regex"] =
+ &::cli::thunk< options, std::vector<std::string>, &options::link_regex_,
+ &options::link_regex_specified_ >;
+ _cli_options_map_["--link-regex-trace"] =
+ &::cli::thunk< options, bool, &options::link_regex_trace_ >;
_cli_options_map_["--hxx-prologue"] =
&::cli::thunk< options, std::vector<std::string>, &options::hxx_prologue_,
&options::hxx_prologue_specified_ >;
diff --git a/cli/options.hxx b/cli/options.hxx
index 1793343..5edd480 100644
--- a/cli/options.hxx
+++ b/cli/options.hxx
@@ -514,6 +514,15 @@ class options
docvar_specified () const;
const std::vector<std::string>&
+ link_regex () const;
+
+ bool
+ link_regex_specified () const;
+
+ const bool&
+ link_regex_trace () const;
+
+ const std::vector<std::string>&
hxx_prologue () const;
bool
@@ -803,6 +812,9 @@ class options
bool class__specified_;
std::map<std::string, std::string> docvar_;
bool docvar_specified_;
+ std::vector<std::string> link_regex_;
+ bool link_regex_specified_;
+ bool link_regex_trace_;
std::vector<std::string> hxx_prologue_;
bool hxx_prologue_specified_;
std::vector<std::string> ixx_prologue_;
diff --git a/cli/options.ixx b/cli/options.ixx
index 618d15f..95c1038 100644
--- a/cli/options.ixx
+++ b/cli/options.ixx
@@ -452,6 +452,24 @@ docvar_specified () const
}
inline const std::vector<std::string>& options::
+link_regex () const
+{
+ return this->link_regex_;
+}
+
+inline bool options::
+link_regex_specified () const
+{
+ return this->link_regex_specified_;
+}
+
+inline const bool& options::
+link_regex_trace () const
+{
+ return this->link_regex_trace_;
+}
+
+inline const std::vector<std::string>& options::
hxx_prologue () const
{
return this->hxx_prologue_;