# # # patch "ui.cc" # from [fa29365937f4748f3b5c019e2af9e4a55a973d2a] # to [7c754595d27d3b2e5ea00579d91366135ff3703b] # ============================================================ --- ui.cc fa29365937f4748f3b5c019e2af9e4a55a973d2a +++ ui.cc 7c754595d27d3b2e5ea00579d91366135ff3703b @@ -46,6 +46,7 @@ using std::vector; using std::ofstream; using std::string; using std::vector; +using std::set; using boost::lexical_cast; @@ -1019,6 +1020,243 @@ user_interface::enable_timestamps() timestamps_enabled = true; } +#include "cmd.hh" +#include "app_state.hh" + +static string +man_italic(string const & content) +{ + return "\\fI" + content + "\\fP"; +} + +static string +man_roman(string const & content) +{ + return "\\fR" + content + "\\fP"; +} + +static string +man_bold(string const & content) +{ + return "\\fB" + content + "\\fP"; +} + +static string +man_definition(vector const & labels, string const & content) +{ + string out; + out += ".IP \" " + (*labels.begin()) + "\"\n"; + if (labels.size() > 1) + { + out += ".PD 0\n"; + for (vector::const_iterator i = labels.begin() + 1; + i < labels.end(); ++i) + { + out += ".IP \" " + (*i) + "\"\n"; + } + out += ".PD\n"; + } + out += content + "\n"; + return out; +} + +static string +man_definition(string const & label, string const & content) +{ + vector labels; + labels.push_back(label); + return man_definition(labels, content); +} + +static string +man_indent(string const & content) +{ + return ".RS\n" + content + ".RE\n"; +} + +static string +man_subsection(string const & content) +{ + return ".SS \"" + content + "\"\n"; +} + +static string +man_section(string const & content) +{ + return ".SH \"" + uppercase(content) + "\"\n"; +} + +static string +man_title(string const & title) +{ + return ".TH \"" + title + "\" 1" + "\n"; +} + +static string +get_options_string(options::options_type const & optset, options & opts) +{ + vector names; + vector descriptions; + unsigned int maxnamelen; + + optset.instantiate(&opts).get_usage_strings(names, descriptions, maxnamelen); + + string out; + vector::const_iterator name; + vector::const_iterator desc; + for (name = names.begin(), desc = descriptions.begin(); + name != names.end(); ++name, ++desc) + { + if (name->empty()) + continue; + out += man_definition(*name, *desc); + } + return out; +} + +static string +get_command_tree(options & opts, commands::command const * cmd) +{ + string out; + + commands::command::children_set subcmds = cmd->children(); + for (commands::command::children_set::const_iterator iter = subcmds.begin(); + iter != subcmds.end(); iter++) + { + commands::command * subcmd = *iter; + if (subcmd->hidden()) + continue; + + if (!subcmd->is_leaf()) + { + if (subcmd->parent() == CMD_REF(__root__)) + { + out += man_subsection( + (F("command group '%s'") % subcmd->primary_name()).str() + ); + out += subcmd->desc(); + } + + // we ignore cascaded groups and go right down to the + // individual commands + out += get_command_tree(opts, subcmd); + } + else + { + // this builds a list of already formatted command calls + // which are used as label for the specific command section + vector cmd_calls; + + // + // newline characters in the parameter section mark + // alternative call syntaxes which we expand here, i.e. + // a command "do-foo" with an alias of "foo" and an argument + // list of "BAR\nBAR BAZ" will be expanded to + // + // do-foo BAR + // do-foo BAR BAZ + // foo BAR + // foo BAR BAZ + // + vector params; + if (!subcmd->params().empty()) + split_into_lines(subcmd->params(), params); + + vector main_ident = subcmd->ident(); + typedef set > ident_set; + ident_set idents; + + commands::command::names_set allnames = subcmd->names(); + for (set::const_iterator i = allnames.begin(); + i != allnames.end(); ++i) + { + vector full_ident; + for (vector::const_iterator j = main_ident.begin() + 1; + j < main_ident.end() - 1; ++j) + { + full_ident.push_back((*j)()); + } + full_ident.push_back((*i)()); + idents.insert(full_ident); + } + + for (ident_set::const_iterator i = idents.begin(); + i != idents.end(); ++i) + { + string call, name; + // cannot use join_words here, since this only + // works on containers + join_lines(*i, name, " "); + + if (params.size() == 0) + { + call = man_bold(name); + cmd_calls.push_back(call); + continue; + } + + for (vector::const_iterator j = params.begin(); + j < params.end(); ++j) + { + call = man_bold(name) + " " + *j; + cmd_calls.push_back(call); + } + } + + string cmd_desc; + cmd_desc += format_text(subcmd->desc()) + "\n"; + + // this prints an indented list of available command options + options::options_type cmd_options = + commands::command_options(main_ident); + if (!cmd_options.empty()) + { + cmd_desc += man_indent(get_options_string(cmd_options, opts)); + } + + // compile everything into a man definition + out += man_definition(cmd_calls, cmd_desc); + } + } + return out; +} + +CMD_HIDDEN(manpage, "manpage", "", CMD_REF(informative), "", + N_("Dumps monotone's command tree in a txt2man compatible format"), + "", + options::opts::none) +{ + std::cout << man_title("monotone"); + std::cout << man_section(_("Name")); + + std::cout << _("monotone - a distributed version control system") << "\n"; + std::cout << man_section(_("Synopsis")); + std::cout << man_bold(prog_name) << " " + << man_italic(_("[options...] command [arguments...]")) + << "\n"; + + std::cout << man_section(_("Description")); + std::cout << _("TODO: write a really fancy and catchy description") << "\n"; + + std::cout << man_section(_("Global Options")); + std::cout << get_options_string(options::opts::globals(), app.opts) << "\n"; + + std::cout << man_section(_("Commands")); + std::cout << get_command_tree(app.opts, CMD_REF(__root__)); + + std::cout << man_section(_("See Also")); + std::cout << (F("info %s and the documentation on <%s>") + % prog_name % man_bold("http://monotone.ca/docs")).str() << "\n"; + + std::cout << man_section("Bugs"); + std::cout << (F("Please report bugs to <%s>.") + % man_bold("http://savannah.nongnu.org/bugs/?group=monotone")).str()<< "\n"; + + std::cout << man_section("Authors"); + std::cout << (F("The monotone development team <%s>") + % man_bold("http://www.monotone.ca")).str() << "\n"; +} + // Local Variables: // mode: C++ // fill-column: 76