From 5f7743da2fa5791e624b41ea1a749ccfa58a8f53 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 30 Oct 2015 10:47:45 +0200 Subject: Implement scope documentation generation in HTML --- cli/context.cxx | 7 +- cli/context.hxx | 4 +- cli/html.cxx | 203 ++++++++++--------- cli/man.cxx | 4 +- cli/semantics/elements.hxx | 6 + cli/source.cxx | 6 +- doc/cli-prologue.xhtml | 15 +- doc/cli.xhtml | 480 +++++++++++++++++++++++---------------------- 8 files changed, 380 insertions(+), 345 deletions(-) diff --git a/cli/context.cxx b/cli/context.cxx index 1324b0c..332c22e 100644 --- a/cli/context.cxx +++ b/cli/context.cxx @@ -315,12 +315,13 @@ translate (string const& s, std::set const& set) } string context:: -format (string const& s, output_type ot) +format (output_type ot, string const& s, bool para) { string r; - r.reserve (s.size ()); - bool para (false); + if (para && ot == ot_html) + r += "

"; + bool escape (false); std::stack blocks; // Bit 0: code; 1: italic; 2: bold. diff --git a/cli/context.hxx b/cli/context.hxx index b6ce420..6eeaa3b 100644 --- a/cli/context.hxx +++ b/cli/context.hxx @@ -93,8 +93,10 @@ public: static string translate (string const&, std::set const&); + // If para is true, start a new paragraph. + // static string - format (string const&, output_type); + format (output_type, string const&, bool para); public: static string const& diff --git a/cli/html.cxx b/cli/html.cxx index 1679fd3..dd49a91 100644 --- a/cli/html.cxx +++ b/cli/html.cxx @@ -12,6 +12,98 @@ using namespace std; namespace { + static string + escape_html (string const& s) + { + string r; + r.reserve (s.size ()); + + for (size_t i (0), n (s.size ()); i < n; ++i) + { + switch (s[i]) + { + case '<': + { + r += "<"; + break; + } + case '&': + { + r += "&"; + break; + } + default: + { + r += s[i]; + break; + } + } + } + + return r; + } + + static void + wrap_lines (ostream& os, const string& d, size_t indent) + { + assert (!d.empty ()); + + size_t lim (78 - indent); + string ind (indent, ' '); + + size_t b (0), e (0), i (0); + + for (size_t n (d.size ()); i < n; ++i) + { + if (d[i] == ' ' || d[i] == '\n') + e = i; + + if (d[i] == '\n' || (i - b >= lim && e != b)) + { + os << (b != 0 ? "\n" : "") << ind << string (d, b, e - b); + + if (d[i] == '\n') + os << endl; + + b = e = e + 1; + } + } + + // Write the last line. + // + if (b != i) + os << (b != 0 ? "\n" : "") << ind << string (d, b, i - b); + } + + struct doc: traversal::doc, context + { + doc (context& c) : context (c) {} + + virtual void + traverse (type& ds) + { + // n = 1 - common doc string + // n = 2 - arg string, common doc string + // n > 2 - arg string, usage string, man string + // + size_t n (ds.size ()); + const string& d (n == 1 ? ds[0] : n == 2 ? ds[1] : ds[2]); + + if (d.empty ()) + return; + + std::set arg_set; + if (n > 1) + translate_arg (ds[0], arg_set); + + string s (format (ot_html, escape_html (translate (d, arg_set)), true)); + + wrap_lines (os, s, 2); + os << endl + << endl; + } + }; + struct option: traversal::option, context { option (context& c) : context (c) {} @@ -28,7 +120,7 @@ namespace names& n (o.named ()); - os << "

"; + os << "
"; for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) { @@ -50,7 +142,7 @@ namespace translate_arg ( doc.size () > 0 ? doc[0] : string (""), arg_set)); - os << ' ' << format (escape_html (s), ot_html); + os << ' ' << format (ot_html, escape_html (s), false); } os << "
" << endl; @@ -77,85 +169,14 @@ namespace // Format the documentation string. // - d = format (escape_html (translate (d, arg_set)), ot_html); - - os << "
"; - - if (!d.empty ()) - { - size_t b (0), e (0), i (0); - - for (size_t n (d.size ()); i < n; ++i) - { - if (d[i] == ' ' || d[i] == '\n') - e = i; - - if (d[i] == '\n' || (i - b >= 76 && e != b)) - { - if (b != 0) - { - os << endl - << " "; - } - - os << string (d, b, e - b); - - if (d[i] == '\n') - os << endl; - - b = e = e + 1; - } - } - - // Flush the last line. - // - if (b != i) - { - if (b != 0) - { - os << endl - << " "; - } - - os << string (d, b, i - b); - } - } + d = format (ot_html, escape_html (translate (d, arg_set)), false); - os << "
" << endl + wrap_lines (os, "
" + d + "
", 4); + os << endl << endl; } private: - string - escape_html (string const& s) - { - string r; - r.reserve (s.size ()); - - for (size_t i (0), n (s.size ()); i < n; ++i) - { - switch (s[i]) - { - case '<': - { - r += "<"; - break; - } - case '&': - { - r += "&"; - break; - } - default: - { - r += s[i]; - break; - } - } - } - - return r; - } }; // @@ -165,9 +186,7 @@ namespace class_ (context& c) : context (c), option_ (c) { - *this >> inherits_base_ >> base_ >> inherits_base_; - base_ >> names_option_; - + *this >> inherits_base_ >> *this; names_option_ >> option_; } @@ -177,15 +196,20 @@ namespace if (!options.exclude_base ()) inherits (c, inherits_base_); - names (c, names_option_); + if (!c.names_empty ()) + { + os << "
" << endl; + names (c, names_option_); + os << "
" << endl + << endl; + } } private: + traversal::inherits inherits_base_; + option option_; traversal::names names_option_; - - traversal::class_ base_; - traversal::inherits inherits_base_; }; } @@ -195,18 +219,21 @@ generate_html (context& ctx) traversal::cli_unit unit; traversal::names unit_names; traversal::namespace_ ns; + doc dc (ctx); class_ cl (ctx); - unit >> unit_names >> ns; + unit >> unit_names; + unit_names >> dc; + unit_names >> ns; unit_names >> cl; traversal::names ns_names; - ns >> ns_names >> ns; + ns >> ns_names; + ns_names >> dc; + ns_names >> ns; ns_names >> cl; - ctx.os << "
" << endl; - if (ctx.options.class_ ().empty ()) unit.dispatch (ctx.unit); else @@ -230,6 +257,4 @@ generate_html (context& ctx) } } } - - ctx.os << "
" << endl; } diff --git a/cli/man.cxx b/cli/man.cxx index b6fd7e8..d4ef7c5 100644 --- a/cli/man.cxx +++ b/cli/man.cxx @@ -50,7 +50,7 @@ namespace translate_arg ( doc.size () > 0 ? doc[0] : string (""), arg_set)); - os << ' ' << format (s, ot_man); + os << ' ' << format (ot_man, s, false); } os << "\"" << endl; @@ -77,7 +77,7 @@ namespace // Format the documentation string. // - d = format (translate (d, arg_set), ot_man); + d = format (ot_man, translate (d, arg_set), false); if (!d.empty ()) { diff --git a/cli/semantics/elements.hxx b/cli/semantics/elements.hxx index a0adce0..65a9382 100644 --- a/cli/semantics/elements.hxx +++ b/cli/semantics/elements.hxx @@ -347,6 +347,12 @@ namespace semantics return names_.end (); } + bool + names_empty () const + { + return names_.empty (); + } + virtual names_iterator_pair find (string const& name) const; diff --git a/cli/source.cxx b/cli/source.cxx index d5c3fd3..19cdb82 100644 --- a/cli/source.cxx +++ b/cli/source.cxx @@ -208,7 +208,7 @@ namespace l++; // ' ' seperator if (doc.size () > 0) - l += format (doc[0], ot_plain).size (); + l += format (ot_plain, doc[0], false).size (); else l += 5; // } @@ -268,7 +268,7 @@ namespace if (doc.size () > 0) { - string s (format (doc[0], ot_plain)); + string s (format (ot_plain, doc[0], false)); os << escape_str (s); l += s.size (); } @@ -306,7 +306,7 @@ namespace // Format the documentation string. // - d = format (d, ot_plain); + d = format (ot_plain, d, false); if (!d.empty ()) { diff --git a/doc/cli-prologue.xhtml b/doc/cli-prologue.xhtml index b9e2f30..88d1e6b 100644 --- a/doc/cli-prologue.xhtml +++ b/doc/cli-prologue.xhtml @@ -21,23 +21,16 @@ padding-bottom : 0.0em; } - #commands dt { - padding-top : 0.4em; - } - - #commands dd { - padding-bottom : 0.4em; - padding-left : 2em; + .options { + margin: 1em 0 1em 0; } .options dt { - padding-top : 0.4em; + margin: 1em 0 0 0; } .options dd { - padding-top : 0.1em; - padding-bottom : 0.4em; - padding-left : 1.4em; + margin: .1em 0 0 4.5em; } diff --git a/doc/cli.xhtml b/doc/cli.xhtml index 1e905bc..896f237 100644 --- a/doc/cli.xhtml +++ b/doc/cli.xhtml @@ -21,23 +21,16 @@ padding-bottom : 0.0em; } - #commands dt { - padding-top : 0.4em; - } - - #commands dd { - padding-bottom : 0.4em; - padding-left : 2em; + .options { + margin: 1em 0 1em 0; } .options dt { - padding-top : 0.4em; + margin: 1em 0 0 0; } .options dd { - padding-top : 0.1em; - padding-bottom : 0.4em; - padding-left : 1.4em; + margin: .1em 0 0 4.5em; } @@ -83,244 +76,259 @@ line interface compiler for C++. --> -
-
--help
-
Print usage information and exit.
- -
--version
-
Print version and exit.
- -
--include-path|-I dir
-
Search dir for bracket-included (<>) options - files.
- -
--output-dir|-o dir
-
Write the generated files to dir instead of the current directory.
- -
--generate-modifier
-
Generate option value modifiers in addition to accessors.
- -
--generate-specifier
-
Generate functions for determining whether the option was specified on the - command line.
- -
--generate-parse
-
Generate parse() functions instead of parsing - constructors. This is primarily useful for being able to parse into an - already initialized options class instance, for example, to implement - merging/overriding.
- -
--generate-description
-
Generate the option description list that can be examined at runtime.
+
+
--help
+
Print usage information and exit.
+ +
--version
+
Print version and exit.
+ +
--include-path|-I dir
+
Search dir for bracket-included (<>) + options files.
+ +
--output-dir|-o dir
+
Write the generated files to dir instead of the current + directory.
+ +
--generate-modifier
+
Generate option value modifiers in addition to accessors.
-
--generate-file-scanner
-
Generate the argv_file_scanner implementation. This scanner is - capable of reading command line arguments from the argv array - as well as files specified with command line options.
+
--generate-specifier
+
Generate functions for determining whether the option was specified on + the command line.
-
--suppress-inline
-
Generate all functions non-inline. By default simple functions are made - inline. This option suppresses creation of the inline file.
+
--generate-parse
+
Generate parse() functions instead of parsing + constructors. This is primarily useful for being able to parse into an + already initialized options class instance, for example, to implement + merging/overriding.
-
--ostream-type type
-
Output stream type instead of the default std::ostream - that should be used to print usage and exception information.
+
--generate-description
+
Generate the option description list that can be examined at + runtime.
-
--suppress-undocumented
-
Suppress the generation of documentation entries for undocumented options.
+
--generate-file-scanner
+
Generate the argv_file_scanner implementation. This + scanner is capable of reading command line arguments from the + argv array as well as files specified with command line + options.
-
--suppress-usage
-
Suppress the generation of the usage printing code.
+
--suppress-inline
+
Generate all functions non-inline. By default simple functions are + made inline. This option suppresses creation of the inline file.
-
--long-usage
-
If no short documentation string is provided, use the complete long - documentation string in usage. By default, in this situation only the first - sentence from the long string is used.
+
--ostream-type type
+
Output stream type instead of the default + std::ostream that should be used to print usage and + exception information.
-
--short-usage
-
If specified together with --long-usage, generate both - short and long usage versions. In this mode, the usage printing functions - are called print_short_usage() and - print_long_usage() and for the long usage the long - documentation string is always used, even if the short version is provided.
+
--suppress-undocumented
+
Suppress the generation of documentation entries for undocumented + options.
-
--option-length len
-
Indent option descriptions len characters when printing usage. This - is useful when you have multiple options classes, potentially in separate - files, and would like their usage to have the same indentation level.
+
--suppress-usage
+
Suppress the generation of the usage printing code.
-
--exclude-base
-
Exclude base class information from usage and documentation.
+
--long-usage
+
If no short documentation string is provided, use the complete long + documentation string in usage. By default, in this situation only the + first sentence from the long string is used.
-
--cli-namespace ns
-
Generate the CLI support types in the ns namespace - (cli by default). The namespace can be nested, for - example details::cli. If the namespace is empty, then - the support types are generated in the global namespace.
+
--short-usage
+
If specified together with --long-usage, generate + both short and long usage versions. In this mode, the usage printing + functions are called print_short_usage() and + print_long_usage() and for the long usage the long + documentation string is always used, even if the short version is + provided.
-
--generate-cxx
-
Generate C++ code. If neither --generate-man nor - --generate-html is specified, this mode is assumed by - default.
+
--option-length len
+
Indent option descriptions len characters when printing usage. + This is useful when you have multiple options classes, potentially in + separate files, and would like their usage to have the same indentation + level.
+ +
--exclude-base
+
Exclude base class information from usage and documentation.
+ +
--cli-namespace ns
+
Generate the CLI support types in the ns namespace + (cli by default). The namespace can be nested, for + example details::cli. If the namespace is empty, then + the support types are generated in the global namespace.
+ +
--generate-cxx
+
Generate C++ code. If neither --generate-man nor + --generate-html is specified, this mode is assumed by + default.
+ +
--generate-man
+
Generate documentation in the man page format.
+ +
--generate-html
+
Generate documentation in the HTML format.
+ +
--hxx-prologue text
+
Insert text at the beginning of the generated C++ header + file.
+ +
--ixx-prologue text
+
Insert text at the beginning of the generated C++ inline + file.
+ +
--cxx-prologue text
+
Insert text at the beginning of the generated C++ source + file.
+ +
--man-prologue text
+
Insert text at the beginning of the generated man page + file.
+ +
--html-prologue text
+
Insert text at the beginning of the generated HTML file.
+ +
--hxx-epilogue text
+
Insert text at the end of the generated C++ header file.
+ +
--ixx-epilogue text
+
Insert text at the end of the generated C++ inline file.
+ +
--cxx-epilogue text
+
Insert text at the end of the generated C++ source file.
+ +
--man-epilogue text
+
Insert text at the end of the generated man page text.
+ +
--html-epilogue text
+
Insert text at the end of the generated HTML text.
+ +
--hxx-prologue-file file
+
Insert the content of file at the beginning of the generated + C++ header file.
+ +
--ixx-prologue-file file
+
Insert the content of file at the beginning of the generated + C++ inline file.
+ +
--cxx-prologue-file file
+
Insert the content of file at the beginning of the generated + C++ source file.
+ +
--man-prologue-file file
+
Insert the content of file at the beginning of the generated + man page file.
+ +
--html-prologue-file file
+
Insert the content of file at the beginning of the generated + HTML file.
+ +
--hxx-epilogue-file file
+
Insert the content of file at the end of the generated C++ + header file.
+ +
--ixx-epilogue-file file
+
Insert the content of file at the end of the generated C++ + inline file.
+ +
--cxx-epilogue-file file
+
Insert the content of file at the end of the generated C++ + source file.
+ +
--man-epilogue-file file
+
Insert the content of file at the end of the generated man page + file.
+ +
--html-epilogue-file file
+
Insert the content of file at the end of the generated HTML + file.
+ +
--class fq-name
+
Generate the man page or HTML documentation only for the + fq-name options class. The fq-name name should be a + fully-qualified options class name, for example, + app::options. To generate documentation for multiple + classes, repeat this option and the documentation will be produced in the + order specified. This functionality is useful if you need to assemble + documentation from multiple classes in a specific order or to insert + custom documentation between options belonging to different classes.
+ +
--stdout
+
Write output to STDOUT instead of a file. This option is not valid + when generating C++ code and is normally used to combine generated + documentation for several option classes in a single file.
+ +
--hxx-suffix suffix
+
Use suffix instead of the default .hxx to + construct the name of the generated header file.
+ +
--ixx-suffix suffix
+
Use suffix instead of the default .ixx to + construct the name of the generated inline file.
+ +
--cxx-suffix suffix
+
Use suffix instead of the default .cxx to + construct the name of the generated source file.
+ +
--man-suffix suffix
+
Use suffix instead of the default .1 to + construct the name of the generated man page file.
+ +
--html-suffix suffix
+
Use suffix instead of the default .html to + construct the name of the generated HTML file.
+ +
--option-prefix prefix
+
Use prefix instead of the default - as an + option prefix. Unknown command line arguments that start with this prefix + are treated as unknown options. If you set the option prefix to the empty + value, then all the unknown command line arguments will be treated as + program arguments.
+ +
--option-separator sep
+
Use sep instead of the default -- as an + optional separator between options and arguments. All the command line + arguments that are parsed after this separator are treated as program + arguments. Set the option separator to the empty value if you don't want + this functionality.
+ +
--include-with-brackets
+
Use angle brackets (<>) instead of quotes ("") in the generated + #include directives.
+ +
--include-prefix prefix
+
Add prefix to the generated #include + directive paths.
+ +
--guard-prefix prefix
+
Add prefix to the generated header inclusion guards. The prefix + is transformed to upper case and characters that are illegal in a + preprocessor macro name are replaced with underscores.
+ +
--reserved-name name=rep
+
Add name with an optional rep replacement to the list of + names that should not be used as identifiers. If provided, the replacement + name is used instead. All C++ keywords are already in this list.
+ +
--options-file file
+
Read additional options from file with each option appearing on + a separate line optionally followed by space and an option value. Empty + lines and lines starting with # are ignored. Option + values can be enclosed in double (") or single + (') quotes to preserve leading and trailing + whitespaces as well as to specify empty values. If the value itself + contains trailing or leading quotes, enclose it with an extra pair of + quotes, for example '"x"'. Non-leading and + non-trailing quotes are interpreted as being part of the option value. + +

The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the point + where the --options-file option is specified except + that the shell escaping and quoting is not required. Repeat this option to + specify more than one options file.

-
--generate-man
-
Generate documentation in the man page format.
- -
--generate-html
-
Generate documentation in the HTML format.
- -
--hxx-prologue text
-
Insert text at the beginning of the generated C++ header file.
- -
--ixx-prologue text
-
Insert text at the beginning of the generated C++ inline file.
- -
--cxx-prologue text
-
Insert text at the beginning of the generated C++ source file.
- -
--man-prologue text
-
Insert text at the beginning of the generated man page file.
- -
--html-prologue text
-
Insert text at the beginning of the generated HTML file.
- -
--hxx-epilogue text
-
Insert text at the end of the generated C++ header file.
- -
--ixx-epilogue text
-
Insert text at the end of the generated C++ inline file.
- -
--cxx-epilogue text
-
Insert text at the end of the generated C++ source file.
+
-
--man-epilogue text
-
Insert text at the end of the generated man page text.
- -
--html-epilogue text
-
Insert text at the end of the generated HTML text.
- -
--hxx-prologue-file file
-
Insert the content of file at the beginning of the generated C++ - header file.
- -
--ixx-prologue-file file
-
Insert the content of file at the beginning of the generated C++ - inline file.
- -
--cxx-prologue-file file
-
Insert the content of file at the beginning of the generated C++ - source file.
- -
--man-prologue-file file
-
Insert the content of file at the beginning of the generated man page - file.
- -
--html-prologue-file file
-
Insert the content of file at the beginning of the generated HTML - file.
- -
--hxx-epilogue-file file
-
Insert the content of file at the end of the generated C++ header - file.
- -
--ixx-epilogue-file file
-
Insert the content of file at the end of the generated C++ inline - file.
- -
--cxx-epilogue-file file
-
Insert the content of file at the end of the generated C++ source - file.
- -
--man-epilogue-file file
-
Insert the content of file at the end of the generated man page file.
- -
--html-epilogue-file file
-
Insert the content of file at the end of the generated HTML file.
- -
--class fq-name
-
Generate the man page or HTML documentation only for the fq-name - options class. The fq-name name should be a fully-qualified options - class name, for example, app::options. To generate - documentation for multiple classes, repeat this option and the documentation - will be produced in the order specified. This functionality is useful if you - need to assemble documentation from multiple classes in a specific order or - to insert custom documentation between options belonging to different - classes.
- -
--stdout
-
Write output to STDOUT instead of a file. This option is not valid when - generating C++ code and is normally used to combine generated documentation - for several option classes in a single file.
- -
--hxx-suffix suffix
-
Use suffix instead of the default .hxx to - construct the name of the generated header file.
- -
--ixx-suffix suffix
-
Use suffix instead of the default .ixx to - construct the name of the generated inline file.
- -
--cxx-suffix suffix
-
Use suffix instead of the default .cxx to - construct the name of the generated source file.
- -
--man-suffix suffix
-
Use suffix instead of the default .1 to construct - the name of the generated man page file.
- -
--html-suffix suffix
-
Use suffix instead of the default .html to - construct the name of the generated HTML file.
- -
--option-prefix prefix
-
Use prefix instead of the default - as an option - prefix. Unknown command line arguments that start with this prefix are - treated as unknown options. If you set the option prefix to the empty value, - then all the unknown command line arguments will be treated as program - arguments.
- -
--option-separator sep
-
Use sep instead of the default -- as an optional - separator between options and arguments. All the command line arguments that - are parsed after this separator are treated as program arguments. Set the - option separator to the empty value if you don't want this functionality.
- -
--include-with-brackets
-
Use angle brackets (<>) instead of quotes ("") in the generated - #include directives.
- -
--include-prefix prefix
-
Add prefix to the generated #include directive - paths.
- -
--guard-prefix prefix
-
Add prefix to the generated header inclusion guards. The prefix is - transformed to upper case and characters that are illegal in a preprocessor - macro name are replaced with underscores.
- -
--reserved-name name=rep
-
Add name with an optional rep replacement to the list of names - that should not be used as identifiers. If provided, the replacement name is - used instead. All C++ keywords are already in this list.
- -
--options-file file
-
Read additional options from file with each option appearing on a - separate line optionally followed by space and an option value. Empty lines - and lines starting with # are ignored. Option values can - be enclosed in double (") or single - (') quotes to preserve leading and trailing whitespaces - as well as to specify empty values. If the value itself contains trailing or - leading quotes, enclose it with an extra pair of quotes, for example - '"x"'. Non-leading and non-trailing quotes are - interpreted as being part of the option value. - -

The semantics of providing options in a file is equivalent to providing - the same set of options in the same order on the command line at the point - where the --options-file option is specified except that - the shell escaping and quoting is not required. Repeat this option to - specify more than one options file.

- -

DIAGNOSTICS

If the input file is not a valid CLI definition, cli -- cgit v1.1