From 5a01a260c368d3045f0870cc09620a772027e911 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 18 Jan 2016 12:50:12 +0200 Subject: Initial support for plain text documentation (--generate-txt) Support for option documentation generation is still a TODO. --- cli/buildfile | 2 +- cli/generator.cxx | 47 +++++++++- cli/makefile | 1 + cli/options.cli | 66 +++++++++++--- cli/options.cxx | 109 +++++++++++++++++++++- cli/options.hxx | 44 +++++++++ cli/options.ixx | 66 ++++++++++++++ cli/source.cxx | 121 +++--------------------- cli/txt.cxx | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/txt.hxx | 44 +++++++++ 10 files changed, 638 insertions(+), 130 deletions(-) create mode 100644 cli/txt.cxx create mode 100644 cli/txt.hxx (limited to 'cli') diff --git a/cli/buildfile b/cli/buildfile index d221237..95f5d14 100644 --- a/cli/buildfile +++ b/cli/buildfile @@ -5,6 +5,6 @@ trav = traversal/{class elements namespace option unit} exe{cli}: cxx{cli generator html lexer name-processor parser runtime-inline \ source context header inline man options runtime-header runtime-source \ -option-types $sema $trav} $libs +txt option-types $sema $trav} $libs cxx.poptions += -I$out_base -I$src_base diff --git a/cli/generator.cxx b/cli/generator.cxx index b086089..486c793 100644 --- a/cli/generator.cxx +++ b/cli/generator.cxx @@ -23,6 +23,7 @@ #include "man.hxx" #include "html.hxx" +#include "txt.hxx" #include "context.hxx" #include "generator.hxx" @@ -122,8 +123,9 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) bool gen_cxx (ops.generate_cxx ()); bool gen_man (ops.generate_man ()); bool gen_html (ops.generate_html ()); + bool gen_txt (ops.generate_txt ()); - if (!gen_cxx && !gen_man && !gen_html) + if (!gen_cxx && !gen_man && !gen_html && !gen_txt) gen_cxx = true; if (ops.stdout_ ()) @@ -134,9 +136,11 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) throw failed (); } - if (gen_man && gen_html) + if ((gen_man && gen_html) || + (gen_man && gen_txt) || + (gen_html && gen_txt)) { - cerr << "error: --stdout cannot be used with man and html output" + cerr << "error: --stdout cannot only be used with one output format" << endl; throw failed (); } @@ -463,6 +467,43 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) append (os, ops.html_epilogue (), ops.html_epilogue_file (), unit); } + // txt output + // + if (gen_txt) + { + ofstream txt; + + if (!ops.stdout_ ()) + { + path txt_path (pfx + base + sfx + ops.txt_suffix ()); + + if (!ops.output_dir ().empty ()) + txt_path = path (ops.output_dir ()) / txt_path; + + txt.open (txt_path.string ().c_str ()); + + if (!txt.is_open ()) + { + cerr << "error: unable to open '" << txt_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (txt_path); + } + + // The explicit cast helps VC++ 8.0 overcome its issues. + // + ostream& os (ops.stdout_ () ? cout : static_cast (txt)); + + append (os, ops.txt_prologue (), ops.txt_prologue_file (), unit); + + context ctx (os, unit, ops); + generate_txt (ctx); + + append (os, ops.txt_epilogue (), ops.txt_epilogue_file (), unit); + } + auto_rm.cancel (); } catch (const generation_failed&) diff --git a/cli/makefile b/cli/makefile index 3b29fdc..3c99e19 100644 --- a/cli/makefile +++ b/cli/makefile @@ -19,6 +19,7 @@ runtime-inline.cxx \ runtime-source.cxx \ man.cxx \ html.cxx \ +txt.cxx \ generator.cxx \ name-processor.cxx diff --git a/cli/options.cli b/cli/options.cli index 32a2794..20e1987 100644 --- a/cli/options.cli +++ b/cli/options.cli @@ -92,8 +92,8 @@ class options bool --generate-cxx { - "Generate C++ code. If neither \cb{--generate-man} nor \cb{--generate-html} - is specified, this mode is assumed by default." + "Generate C++ code. If neither \cb{--generate-man}, \cb{--generate-html}, + nor \cb{--generate-txt} is specified, this mode is assumed by default." }; bool --generate-man @@ -106,6 +106,11 @@ class options "Generate documentation in the HTML format." }; + bool --generate-txt + { + "Generate documentation in the plain text format, similar to usage." + }; + bool --stdout { "Write output to STDOUT instead of a file. This option is not valid @@ -198,23 +203,24 @@ class options class . The value should be a fully-qualified class name, for example, \cb{app::options}. The value can be \cb{short}, \cb{long}, or \cb{exclude}. If the value is \cb{exclude}, then the - class documentation is excluded from usage and man/HTML output. For + class documentation is excluded from usage and man/HTML/text output. For usage, the \cb{short} and \cb{long} values determine which usage function will be called when the class is used as base or as part of - the page usage (see \cb{--page-usage}). For man/HTML, these values + the page usage (see \cb{--page-usage}). For man/HTML/text, these values determine which documentation strings are used in the output." }; std::vector --class { "", - "Generate the man page or HTML documentation only for the options class - . The value should be a fully-qualified options class name, - for example, \cb{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." + "Generate the man page, HTML, or text documentation only for the options + class . The value should be a fully-qualified options class + name, for example, \cb{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." }; std::map --docvar|-v @@ -260,6 +266,12 @@ class options "Insert at the beginning of the generated HTML file." }; + std::vector --txt-prologue + { + "", + "Insert at the beginning of the generated text file." + }; + // Epilogues. // std::vector --hxx-epilogue @@ -283,13 +295,19 @@ class options std::vector --man-epilogue { "", - "Insert at the end of the generated man page text." + "Insert at the end of the generated man page file." }; std::vector --html-epilogue { "", - "Insert at the end of the generated HTML text." + "Insert at the end of the generated HTML file." + }; + + std::vector --txt-epilogue + { + "", + "Insert at the end of the generated text file." }; // Prologue files. @@ -329,6 +347,13 @@ class options file." }; + std::string --txt-prologue-file + { + "", + "Insert the content of at the beginning of the generated text + file." + }; + // Epilogue files. // std::string --hxx-epilogue-file @@ -364,6 +389,14 @@ class options "Insert the content of at the end of the generated HTML file." }; + std::string --txt-epilogue-file + { + "", + "Insert the content of at the end of the generated text file." + }; + + // Output. + // std::string --output-prefix { "", @@ -413,6 +446,13 @@ class options of the generated HTML file." }; + std::string --txt-suffix = ".txt" + { + "", + "Use instead of the default \cb{.txt} to construct the name of + the generated text file." + }; + std::string --option-prefix = "-" { "", diff --git a/cli/options.cxx b/cli/options.cxx index 118d8ee..0be47dc 100644 --- a/cli/options.cxx +++ b/cli/options.cxx @@ -582,6 +582,7 @@ options () generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -610,6 +611,8 @@ options () man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -620,6 +623,8 @@ options () man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -630,6 +635,8 @@ options () man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -640,6 +647,8 @@ options () man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -654,6 +663,8 @@ options () man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -697,6 +708,7 @@ options (int& argc, generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -725,6 +737,8 @@ options (int& argc, man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -735,6 +749,8 @@ options (int& argc, man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -745,6 +761,8 @@ options (int& argc, man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -755,6 +773,8 @@ options (int& argc, man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -769,6 +789,8 @@ options (int& argc, man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -815,6 +837,7 @@ options (int start, generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -843,6 +866,8 @@ options (int start, man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -853,6 +878,8 @@ options (int start, man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -863,6 +890,8 @@ options (int start, man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -873,6 +902,8 @@ options (int start, man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -887,6 +918,8 @@ options (int start, man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -933,6 +966,7 @@ options (int& argc, generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -961,6 +995,8 @@ options (int& argc, man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -971,6 +1007,8 @@ options (int& argc, man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -981,6 +1019,8 @@ options (int& argc, man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -991,6 +1031,8 @@ options (int& argc, man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -1005,6 +1047,8 @@ options (int& argc, man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1053,6 +1097,7 @@ options (int start, generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1081,6 +1126,8 @@ options (int start, man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -1091,6 +1138,8 @@ options (int start, man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -1101,6 +1150,8 @@ options (int start, man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -1111,6 +1162,8 @@ options (int start, man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -1125,6 +1178,8 @@ options (int start, man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1169,6 +1224,7 @@ options (::cli::scanner& s, generate_cxx_ (), generate_man_ (), generate_html_ (), + generate_txt_ (), stdout__ (), suppress_undocumented_ (), suppress_usage_ (), @@ -1197,6 +1253,8 @@ options (::cli::scanner& s, man_prologue_specified_ (false), html_prologue_ (), html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), hxx_epilogue_ (), hxx_epilogue_specified_ (false), ixx_epilogue_ (), @@ -1207,6 +1265,8 @@ options (::cli::scanner& s, man_epilogue_specified_ (false), html_epilogue_ (), html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), hxx_prologue_file_ (), hxx_prologue_file_specified_ (false), ixx_prologue_file_ (), @@ -1217,6 +1277,8 @@ options (::cli::scanner& s, man_prologue_file_specified_ (false), html_prologue_file_ (), html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), hxx_epilogue_file_ (), hxx_epilogue_file_specified_ (false), ixx_epilogue_file_ (), @@ -1227,6 +1289,8 @@ options (::cli::scanner& s, man_epilogue_file_specified_ (false), html_epilogue_file_ (), html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), output_prefix_ (), output_prefix_specified_ (false), output_suffix_ (), @@ -1241,6 +1305,8 @@ options (::cli::scanner& s, man_suffix_specified_ (false), html_suffix_ (".html"), html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), option_prefix_ ("-"), option_prefix_specified_ (false), option_separator_ ("--"), @@ -1308,6 +1374,9 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--generate-html Generate documentation in the HTML format." << ::std::endl; + os << "--generate-txt Generate documentation in the plain text format," << ::std::endl + << " similar to usage." << ::std::endl; + os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; os << "--suppress-undocumented Suppress the generation of documentation entries" << ::std::endl @@ -1340,8 +1409,8 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--class-doc = Specify the documentation that should be" << ::std::endl << " used for the options class ." << ::std::endl; - os << "--class Generate the man page or HTML documentation only" << ::std::endl - << " for the options class ." << ::std::endl; + os << "--class Generate the man page, HTML, or text documentation" << ::std::endl + << " only for the options class ." << ::std::endl; os << "--docvar|-v = Set documentation variable to the value" << ::std::endl << " ." << ::std::endl; @@ -1361,6 +1430,9 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--html-prologue Insert at the beginning of the generated" << ::std::endl << " HTML file." << ::std::endl; + os << "--txt-prologue Insert at the beginning of the generated" << ::std::endl + << " text file." << ::std::endl; + os << "--hxx-epilogue Insert at the end of the generated C++" << ::std::endl << " header file." << ::std::endl; @@ -1371,10 +1443,13 @@ print_usage (::std::ostream& os, ::cli::usage_para p) << " source file." << ::std::endl; os << "--man-epilogue Insert at the end of the generated man page" << ::std::endl - << " text." << ::std::endl; + << " file." << ::std::endl; os << "--html-epilogue Insert at the end of the generated HTML" << ::std::endl - << " text." << ::std::endl; + << " file." << ::std::endl; + + os << "--txt-epilogue Insert at the end of the generated text" << ::std::endl + << " file." << ::std::endl; os << "--hxx-prologue-file Insert the content of at the beginning of" << ::std::endl << " the generated C++ header file." << ::std::endl; @@ -1391,6 +1466,9 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--html-prologue-file Insert the content of at the beginning of" << ::std::endl << " the generated HTML file." << ::std::endl; + os << "--txt-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated text file." << ::std::endl; + os << "--hxx-epilogue-file Insert the content of at the end of the" << ::std::endl << " generated C++ header file." << ::std::endl; @@ -1406,6 +1484,9 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--html-epilogue-file Insert the content of at the end of the" << ::std::endl << " generated HTML file." << ::std::endl; + os << "--txt-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated text file." << ::std::endl; + os << "--output-prefix Add at the beginning of the generated" << ::std::endl << " output file name(s)." << ::std::endl; @@ -1427,6 +1508,9 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--html-suffix Use instead of the default '.html' to" << ::std::endl << " construct the name of the generated HTML file." << ::std::endl; + os << "--txt-suffix Use instead of the default '.txt' to" << ::std::endl + << " construct the name of the generated text file." << ::std::endl; + os << "--option-prefix Use instead of the default '-' as an" << ::std::endl << " option prefix." << ::std::endl; @@ -1508,6 +1592,8 @@ struct _cli_options_map_init &::cli::thunk< options, bool, &options::generate_man_ >; _cli_options_map_["--generate-html"] = &::cli::thunk< options, bool, &options::generate_html_ >; + _cli_options_map_["--generate-txt"] = + &::cli::thunk< options, bool, &options::generate_txt_ >; _cli_options_map_["--stdout"] = &::cli::thunk< options, bool, &options::stdout__ >; _cli_options_map_["--suppress-undocumented"] = @@ -1557,6 +1643,9 @@ struct _cli_options_map_init _cli_options_map_["--html-prologue"] = &::cli::thunk< options, std::vector, &options::html_prologue_, &options::html_prologue_specified_ >; + _cli_options_map_["--txt-prologue"] = + &::cli::thunk< options, std::vector, &options::txt_prologue_, + &options::txt_prologue_specified_ >; _cli_options_map_["--hxx-epilogue"] = &::cli::thunk< options, std::vector, &options::hxx_epilogue_, &options::hxx_epilogue_specified_ >; @@ -1572,6 +1661,9 @@ struct _cli_options_map_init _cli_options_map_["--html-epilogue"] = &::cli::thunk< options, std::vector, &options::html_epilogue_, &options::html_epilogue_specified_ >; + _cli_options_map_["--txt-epilogue"] = + &::cli::thunk< options, std::vector, &options::txt_epilogue_, + &options::txt_epilogue_specified_ >; _cli_options_map_["--hxx-prologue-file"] = &::cli::thunk< options, std::string, &options::hxx_prologue_file_, &options::hxx_prologue_file_specified_ >; @@ -1587,6 +1679,9 @@ struct _cli_options_map_init _cli_options_map_["--html-prologue-file"] = &::cli::thunk< options, std::string, &options::html_prologue_file_, &options::html_prologue_file_specified_ >; + _cli_options_map_["--txt-prologue-file"] = + &::cli::thunk< options, std::string, &options::txt_prologue_file_, + &options::txt_prologue_file_specified_ >; _cli_options_map_["--hxx-epilogue-file"] = &::cli::thunk< options, std::string, &options::hxx_epilogue_file_, &options::hxx_epilogue_file_specified_ >; @@ -1602,6 +1697,9 @@ struct _cli_options_map_init _cli_options_map_["--html-epilogue-file"] = &::cli::thunk< options, std::string, &options::html_epilogue_file_, &options::html_epilogue_file_specified_ >; + _cli_options_map_["--txt-epilogue-file"] = + &::cli::thunk< options, std::string, &options::txt_epilogue_file_, + &options::txt_epilogue_file_specified_ >; _cli_options_map_["--output-prefix"] = &::cli::thunk< options, std::string, &options::output_prefix_, &options::output_prefix_specified_ >; @@ -1623,6 +1721,9 @@ struct _cli_options_map_init _cli_options_map_["--html-suffix"] = &::cli::thunk< options, std::string, &options::html_suffix_, &options::html_suffix_specified_ >; + _cli_options_map_["--txt-suffix"] = + &::cli::thunk< options, std::string, &options::txt_suffix_, + &options::txt_suffix_specified_ >; _cli_options_map_["--option-prefix"] = &::cli::thunk< options, std::string, &options::option_prefix_, &options::option_prefix_specified_ >; diff --git a/cli/options.hxx b/cli/options.hxx index 9794732..1793343 100644 --- a/cli/options.hxx +++ b/cli/options.hxx @@ -457,6 +457,9 @@ class options generate_html () const; const bool& + generate_txt () const; + + const bool& stdout_ () const; const bool& @@ -541,6 +544,12 @@ class options html_prologue_specified () const; const std::vector& + txt_prologue () const; + + bool + txt_prologue_specified () const; + + const std::vector& hxx_epilogue () const; bool @@ -570,6 +579,12 @@ class options bool html_epilogue_specified () const; + const std::vector& + txt_epilogue () const; + + bool + txt_epilogue_specified () const; + const std::string& hxx_prologue_file () const; @@ -601,6 +616,12 @@ class options html_prologue_file_specified () const; const std::string& + txt_prologue_file () const; + + bool + txt_prologue_file_specified () const; + + const std::string& hxx_epilogue_file () const; bool @@ -631,6 +652,12 @@ class options html_epilogue_file_specified () const; const std::string& + txt_epilogue_file () const; + + bool + txt_epilogue_file_specified () const; + + const std::string& output_prefix () const; bool @@ -673,6 +700,12 @@ class options html_suffix_specified () const; const std::string& + txt_suffix () const; + + bool + txt_suffix_specified () const; + + const std::string& option_prefix () const; bool @@ -751,6 +784,7 @@ class options bool generate_cxx_; bool generate_man_; bool generate_html_; + bool generate_txt_; bool stdout__; bool suppress_undocumented_; bool suppress_usage_; @@ -779,6 +813,8 @@ class options bool man_prologue_specified_; std::vector html_prologue_; bool html_prologue_specified_; + std::vector txt_prologue_; + bool txt_prologue_specified_; std::vector hxx_epilogue_; bool hxx_epilogue_specified_; std::vector ixx_epilogue_; @@ -789,6 +825,8 @@ class options bool man_epilogue_specified_; std::vector html_epilogue_; bool html_epilogue_specified_; + std::vector txt_epilogue_; + bool txt_epilogue_specified_; std::string hxx_prologue_file_; bool hxx_prologue_file_specified_; std::string ixx_prologue_file_; @@ -799,6 +837,8 @@ class options bool man_prologue_file_specified_; std::string html_prologue_file_; bool html_prologue_file_specified_; + std::string txt_prologue_file_; + bool txt_prologue_file_specified_; std::string hxx_epilogue_file_; bool hxx_epilogue_file_specified_; std::string ixx_epilogue_file_; @@ -809,6 +849,8 @@ class options bool man_epilogue_file_specified_; std::string html_epilogue_file_; bool html_epilogue_file_specified_; + std::string txt_epilogue_file_; + bool txt_epilogue_file_specified_; std::string output_prefix_; bool output_prefix_specified_; std::string output_suffix_; @@ -823,6 +865,8 @@ class options bool man_suffix_specified_; std::string html_suffix_; bool html_suffix_specified_; + std::string txt_suffix_; + bool txt_suffix_specified_; std::string option_prefix_; bool option_prefix_specified_; std::string option_separator_; diff --git a/cli/options.ixx b/cli/options.ixx index ed07f19..618d15f 100644 --- a/cli/options.ixx +++ b/cli/options.ixx @@ -338,6 +338,12 @@ generate_html () const } inline const bool& options:: +generate_txt () const +{ + return this->generate_txt_; +} + +inline const bool& options:: stdout_ () const { return this->stdout__; @@ -506,6 +512,18 @@ html_prologue_specified () const } inline const std::vector& options:: +txt_prologue () const +{ + return this->txt_prologue_; +} + +inline bool options:: +txt_prologue_specified () const +{ + return this->txt_prologue_specified_; +} + +inline const std::vector& options:: hxx_epilogue () const { return this->hxx_epilogue_; @@ -565,6 +583,18 @@ html_epilogue_specified () const return this->html_epilogue_specified_; } +inline const std::vector& options:: +txt_epilogue () const +{ + return this->txt_epilogue_; +} + +inline bool options:: +txt_epilogue_specified () const +{ + return this->txt_epilogue_specified_; +} + inline const std::string& options:: hxx_prologue_file () const { @@ -626,6 +656,18 @@ html_prologue_file_specified () const } inline const std::string& options:: +txt_prologue_file () const +{ + return this->txt_prologue_file_; +} + +inline bool options:: +txt_prologue_file_specified () const +{ + return this->txt_prologue_file_specified_; +} + +inline const std::string& options:: hxx_epilogue_file () const { return this->hxx_epilogue_file_; @@ -686,6 +728,18 @@ html_epilogue_file_specified () const } inline const std::string& options:: +txt_epilogue_file () const +{ + return this->txt_epilogue_file_; +} + +inline bool options:: +txt_epilogue_file_specified () const +{ + return this->txt_epilogue_file_specified_; +} + +inline const std::string& options:: output_prefix () const { return this->output_prefix_; @@ -770,6 +824,18 @@ html_suffix_specified () const } inline const std::string& options:: +txt_suffix () const +{ + return this->txt_suffix_; +} + +inline bool options:: +txt_suffix_specified () const +{ + return this->txt_suffix_specified_; +} + +inline const std::string& options:: option_prefix () const { return this->option_prefix_; diff --git a/cli/source.cxx b/cli/source.cxx index 37058da..f8d367e 100644 --- a/cli/source.cxx +++ b/cli/source.cxx @@ -6,6 +6,7 @@ #include #include "source.hxx" +#include "txt.hxx" // txt_size(), txt_wrap_lines() using namespace std; @@ -169,36 +170,6 @@ namespace } }; - - // Return the number of "text characters", ignoring any escape sequences - // (e.g., ANSI color). - // - static size_t - text_size (const string& s, size_t p = 0, size_t n = string::npos) - { - size_t r (0); - - n = n == string::npos ? s.size () : n + p; - - // The start position (p) might be pointing half-way into the - // escape sequence. So we always have to scan from the start. - // - for (size_t i (0), m (s.size ()); i < n; ++i) - { - if (s[i] == '\033') // ANSI escape: "\033[Nm" - { - i += 3; - assert (i < m && s[i] == 'm'); - continue; - } - - if (i >= p) - ++r; - } - - return r; - } - static string escape_str (string const& s) { @@ -234,88 +205,20 @@ namespace return r; } - // This function assumes that the string opening part has already been - // written. The 'first' argument is the number of characters already - // written in the first line (e.g., an option name). - // - static void + inline void wrap_lines (ostream& os, const string& d, size_t indent = 0, size_t first = 0) { - assert (!d.empty ()); - - os << string (indent - first, ' '); - - // Count the number of leading spaces at the beginning of each line. - // Then use it as an extra indentation if we are breaking this line. - // This makes multi-line definition lists look decent. Note that this - // doesn't work for ordered/unordered lists because they start on the - // same line as number/bullet. However, there is hack to make it work: - // break the first line at the 80 characters boundary explicitly with - // \n. - // - size_t wc (0), wi (0); // Count and count-based indentation. - bool cws (true); // Count flag. - - size_t b (0), e (0), i (0); - for (size_t n (d.size ()); i < n; ++i) - { - char c (d[i]); - - if (c == ' ' || c == '\n') - e = i; - - if (c == '\n' || text_size (d, b, i - b) == 79 - indent - wi) - { - if (b != 0) // Not a first line. - os << endl - << " << \"" << string (indent + wi, ' '); - - string s (d, b, (e != b ? e : i) - b); - os << escape_str (s) << "\" << ::std::endl"; - - // Handle consecutive newlines (e.g., pre, paragraph separator). - // - if (c == '\n') - { - for (; i + 1 < n && d[i + 1] == '\n'; e = ++i) - os << endl - << " << ::std::endl"; - } - - b = e = (e != b ? e : i) + 1; - wi = wc; // Start indent beginning with the next break. - } - - if (c == '\n') - { - // Reset and start counting. - // - wc = wi = 0; - cws = true; - } - else if (cws) - { - if (c == ' ') - ++wc; - else - cws = false; - } - } - - // Flush the last line. - // - if (b != i) - { - if (b != 0) - os << endl - << " << \"" << string (indent + wi, ' '); - - string s (d, b, i - b); - os << escape_str (s) << "\" << ::std::endl"; - } + txt_wrap_lines (os, + d, + indent, + first, + " << \"", // line_start + "\" << ::std::endl", // line_end + " << ::std::endl", // line_blank + &escape_str); } enum paragraph {para_unknown, para_text, para_option}; @@ -428,7 +331,7 @@ namespace s = translate_arg (s, arg_set); } - l += text_size (format (ot_plain, s, false)); + l += txt_size (format (ot_plain, s, false)); } if (l > length_) @@ -522,7 +425,7 @@ namespace s = format (ot_plain, s, false); os << escape_str (s); - l += text_size (s); + l += txt_size (s); } // Figure out which documentation string we should use. diff --git a/cli/txt.cxx b/cli/txt.cxx new file mode 100644 index 0000000..c537c55 --- /dev/null +++ b/cli/txt.cxx @@ -0,0 +1,268 @@ +// file : cli/txt.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include "txt.hxx" + +using namespace std; + +size_t +txt_size (const string& s, size_t p, size_t n) +{ + size_t r (0); + + n = n == string::npos ? s.size () : n + p; + + // The start position (p) might be pointing half-way into the + // escape sequence. So we always have to scan from the start. + // + for (size_t i (0), m (s.size ()); i < n; ++i) + { + if (s[i] == '\033') // ANSI escape: "\033[Nm" + { + i += 3; + assert (i < m && s[i] == 'm'); + continue; + } + + if (i >= p) + ++r; + } + + return r; +} + +void +txt_wrap_lines (ostream& os, + const string& d, + size_t indent, + size_t first, + const char* line_start, + const char* line_end, + const char* line_blank, + string (*escape) (string const&)) +{ + assert (!d.empty ()); + + os << string (indent - first, ' '); + + // Count the number of leading spaces at the beginning of each line. + // Then use it as an extra indentation if we are breaking this line. + // This makes multi-line definition lists look decent. Note that this + // doesn't work for ordered/unordered lists because they start on the + // same line as number/bullet. However, there is hack to make it work: + // break the first line at the 80 characters boundary explicitly with + // \n. + // + size_t wc (0), wi (0); // Count and count-based indentation. + bool cws (true); // Count flag. + + size_t b (0), e (0), i (0); + for (size_t n (d.size ()); i < n; ++i) + { + char c (d[i]); + + if (c == ' ' || c == '\n') + e = i; + + if (c == '\n' || txt_size (d, b, i - b) == 79 - indent - wi) + { + if (b != 0) // Not a first line. + os << endl + << line_start << string (indent + wi, ' '); + + string s (d, b, (e != b ? e : i) - b); + + if (escape != 0) + s = escape (s); + + os << s << line_end; + + // Handle consecutive newlines (e.g., pre, paragraph separator). + // + if (c == '\n') + { + for (; i + 1 < n && d[i + 1] == '\n'; e = ++i) + os << endl + << line_blank; + } + + b = e = (e != b ? e : i) + 1; + wi = wc; // Start indent beginning with the next break. + } + + if (c == '\n') + { + // Reset and start counting. + // + wc = wi = 0; + cws = true; + } + else if (cws) + { + if (c == ' ') + ++wc; + else + cws = false; + } + } + + // Flush the last line. + // + if (b != i) + { + if (b != 0) + os << endl + << line_start << string (indent + wi, ' '); + + string s (d, b, i - b); + + if (escape != 0) + s = escape (s); + + os << s << line_end; + } +} + +namespace +{ + struct doc: traversal::doc, context + { + doc (context& c, class_doc_type cd): context (c), cd_ (cd) {} + + virtual void + traverse (type& ds) + { + if (ds.name ().compare (0, 3, "doc") != 0) // Ignore doc variables. + return; + + // n = 1 - common doc string + // n = 2 - arg string, common doc string + // n > 2 - arg string, short string, long string + // + size_t n (ds.size ()); + const string& d ( + n == 1 + ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) + : (n == 2 + ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) + : ds[cd_ == cd_short ? 1 : 2])); + + std::set arg_set; + if (n > 1 && options.ansi_color ()) + translate_arg (ds[0], arg_set); + + string s (format (ot_plain, translate (d, arg_set), true)); + + if (s.empty ()) + return; + + txt_wrap_lines (os, s); + os << endl; //@@ ?? + } + + private: + class_doc_type cd_; + }; + + struct option: traversal::option, context + { + option (context& c, class_doc_type cd) : context (c), cd_ (cd) {} + + virtual void + traverse (type& o) + { + using semantics::names; + + semantics::doc_strings const& doc (o.doc ()); + + if (options.suppress_undocumented () && doc.empty ()) + return; + + //@@ TODO + } + + private: + class_doc_type cd_; + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c): context (c) {*this >> inherits_ >> *this;} + + virtual void + traverse (type& c) + { + class_doc_type cd (class_doc (c)); + + if (cd == cd_exclude) + return; + + if (!options.exclude_base () && !options.include_base_last ()) + inherits (c); + + doc dc (*this, cd); + option op (*this, cd); + traversal::names n; + n >> dc; + n >> op; + names (c, n); + + if (!options.exclude_base () && options.include_base_last ()) + inherits (c); + } + + private: + traversal::inherits inherits_; + }; +} + +void +generate_txt (context& ctx) +{ + traversal::cli_unit unit; + traversal::names unit_names; + traversal::namespace_ ns; + doc dc (ctx, cd_default); + class_ cl (ctx); + unit >> unit_names; + unit_names >> ns; + unit_names >> dc; + unit_names >> cl; + + traversal::names ns_names; + ns >> ns_names; + ns_names >> ns; + ns_names >> dc; + ns_names >> cl; + + if (ctx.options.class_ ().empty ()) + unit.dispatch (ctx.unit); + else + { + for (vector::const_iterator i (ctx.options.class_ ().begin ()); + i != ctx.options.class_ ().end (); ++i) + { + string n (*i); + + // Strip leading :: if present. + // + if (n.size () > 2 && n[0] == ':' && n[1] == ':') + n = string (n, 2, string::npos); + + if (semantics::class_* c = ctx.unit.lookup ("", n)) + cl.traverse (*c); + else + { + cerr << "error: class '" << *i << "' not found" << endl; + throw generation_failed (); + } + } + } +} diff --git a/cli/txt.hxx b/cli/txt.hxx new file mode 100644 index 0000000..b0a667c --- /dev/null +++ b/cli/txt.hxx @@ -0,0 +1,44 @@ +// file : cli/txt.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_TXT_HXX +#define CLI_TXT_HXX + +#include // ostream +#include +#include // size_t + +#include "context.hxx" + +void +generate_txt (context&); + +// Return the number of "text characters", ignoring any escape sequences +// (e.g., ANSI color). +// +std::size_t +txt_size (const std::string&, + std::size_t p = 0, + std::size_t n = std::string::npos); + +// This function assumes that the initial opening part has already been +// written with the 'first' argument being the number of characters already +// written in the first line (e.g., an option name). The 'indent' argument +// specified how many spaces to indent each line. The 'escape' argument is +// the optional escape function (e.g., for the string literal output). The +// line_{start, end, blank} arguments specify optional extra text for the +// start/end of the non-empty line as well as for the blank (empty) line. +// +void +txt_wrap_lines (std::ostream& os, + const std::string&, + std::size_t indent = 0, + std::size_t first = 0, + const char* line_start = "", + const char* line_end = "", + const char* line_blank = "", + std::string (*escape) (std::string const&) = 0); + +#endif // CLI_TXT_HXX -- cgit v1.1