# # # patch "cmd_diff_log.cc" # from [fa9767c8d7388519dbccf9896ebf03749acf005a] # to [2c998d3f717592ee2395f51169bdb02a65118ff8] # # patch "cmd_ws_commit.cc" # from [0aa51a85aef50271b6755e53723ac9e94e49d189] # to [5d0a6628314c487f2f0854257abcb9e396a1635b] # # patch "rev_output.cc" # from [d3979e2e706aaa0fee3947ae424b9e9595460fed] # to [8cb1fadbcd79aab23bf95c26aec3390f4fa950d6] # # patch "rev_output.hh" # from [a81f8b7801fe5adceb0b988fe79f9af7dc85ae8c] # to [04094228d1f6e4828d139f41be4ce6eb6b08b593] # ============================================================ --- cmd_diff_log.cc fa9767c8d7388519dbccf9896ebf03749acf005a +++ cmd_diff_log.cc 2c998d3f717592ee2395f51169bdb02a65118ff8 @@ -22,6 +22,7 @@ #include "restrictions.hh" #include "revision.hh" #include "rev_height.hh" +#include "rev_output.hh" #include "simplestring_xform.hh" #include "transforms.hh" #include "app_state.hh" @@ -41,150 +42,7 @@ using std::priority_queue; using std::vector; using std::priority_queue; -using boost::lexical_cast; - -// The changes_summary structure holds a list all of files and directories -// affected in a revision, and is useful in the 'log' command to print this -// information easily. It has to be constructed from all cset objects -// that belong to a revision. - -struct -changes_summary -{ - cset cs; - changes_summary(void); - void add_change_set(cset const & cs); - void print(ostream & os, size_t max_cols) const; -}; - -changes_summary::changes_summary(void) -{ -} - -void -changes_summary::add_change_set(cset const & c) -{ - if (c.empty()) - return; - - // FIXME: not sure whether it matters for an informal summary - // object like this, but the pre-state names in deletes and renames - // are not really sensible to union; they refer to different trees - // so mixing them up in a single set is potentially ambiguous. - - copy(c.nodes_deleted.begin(), c.nodes_deleted.end(), - inserter(cs.nodes_deleted, cs.nodes_deleted.begin())); - - copy(c.files_added.begin(), c.files_added.end(), - inserter(cs.files_added, cs.files_added.begin())); - - copy(c.dirs_added.begin(), c.dirs_added.end(), - inserter(cs.dirs_added, cs.dirs_added.begin())); - - copy(c.nodes_renamed.begin(), c.nodes_renamed.end(), - inserter(cs.nodes_renamed, cs.nodes_renamed.begin())); - - copy(c.deltas_applied.begin(), c.deltas_applied.end(), - inserter(cs.deltas_applied, cs.deltas_applied.begin())); - - copy(c.attrs_cleared.begin(), c.attrs_cleared.end(), - inserter(cs.attrs_cleared, cs.attrs_cleared.begin())); - - copy(c.attrs_set.begin(), c.attrs_set.end(), - inserter(cs.attrs_set, cs.attrs_set.begin())); -} - static void -print_indented_set(ostream & os, - set const & s, - size_t max_cols) -{ - size_t cols = 8; - os << " "; - for (set::const_iterator i = s.begin(); - i != s.end(); i++) - { - string str = lexical_cast(*i); - if (str.empty()) - str = "."; // project root - if (cols > 8 && cols + str.size() + 1 >= max_cols) - { - cols = 8; - os << "\n "; - } - os << ' ' << str; - cols += str.size() + 1; - } - os << '\n'; -} - -void -changes_summary::print(ostream & os, size_t max_cols) const -{ - - if (! cs.nodes_deleted.empty()) - { - os << _("Deleted entries:") << '\n'; - print_indented_set(os, cs.nodes_deleted, max_cols); - } - - if (! cs.nodes_renamed.empty()) - { - os << _("Renamed entries:") << '\n'; - for (map::const_iterator - i = cs.nodes_renamed.begin(); - i != cs.nodes_renamed.end(); i++) - os << " " << i->first - << " to " << i->second << '\n'; - } - - if (! cs.files_added.empty()) - { - set tmp; - for (map::const_iterator - i = cs.files_added.begin(); - i != cs.files_added.end(); ++i) - tmp.insert(i->first); - os << _("Added files:") << '\n'; - print_indented_set(os, tmp, max_cols); - } - - if (! cs.dirs_added.empty()) - { - os << _("Added directories:") << '\n'; - print_indented_set(os, cs.dirs_added, max_cols); - } - - if (! cs.deltas_applied.empty()) - { - set tmp; - for (map >::const_iterator - i = cs.deltas_applied.begin(); - i != cs.deltas_applied.end(); ++i) - tmp.insert(i->first); - os << _("Modified files:") << '\n'; - print_indented_set(os, tmp, max_cols); - } - - if (! cs.attrs_set.empty() || ! cs.attrs_cleared.empty()) - { - set tmp; - for (set >::const_iterator - i = cs.attrs_cleared.begin(); - i != cs.attrs_cleared.end(); ++i) - tmp.insert(i->first); - - for (map, attr_value>::const_iterator - i = cs.attrs_set.begin(); - i != cs.attrs_set.end(); ++i) - tmp.insert(i->first.first); - - os << _("Modified attrs:") << '\n'; - print_indented_set(os, tmp, max_cols); - } -} - -static void do_external_diff(options & opts, lua_hooks & lua, database & db, cset const & cs, bool new_is_archived) { @@ -613,96 +471,32 @@ log_certs(vector const & certs, os static void log_certs(vector const & certs, ostream & os, cert_name const & name, - char const * label, char const * separator, - bool multiline, bool newline) + string const date_fmt = "") { bool first = true; - if (multiline) - newline = true; - - for (vector::const_iterator i = certs.begin(); - i != certs.end(); ++i) + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) { if (i->name == name) { if (first) - os << label; + os << " "; else - os << separator; + os << ","; - if (multiline) - os << "\n\n"; - os << i->value; - if (newline) - os << '\n'; - - first = false; - } - } -} - -static void -log_certs(vector const & certs, ostream & os, cert_name const & name, - char const * label, bool multiline) -{ - log_certs(certs, os, name, label, label, multiline, true); -} - -static void -log_certs(vector const & certs, ostream & os, cert_name const & name) -{ - log_certs(certs, os, name, " ", ",", false, false); -} - -static void -log_date_certs(vector const & certs, ostream & os, string const & fmt, - char const * label, char const * separator, - bool multiline, bool newline) -{ - cert_name const date_name(date_cert_name); - - bool first = true; - if (multiline) - newline = true; - - for (vector::const_iterator i = certs.begin(); - i != certs.end(); ++i) - { - if (i->name == date_name) - { - if (first) - os << label; - else - os << separator; - - if (multiline) - os << "\n\n"; - if (fmt.empty()) + if (date_fmt.empty()) os << i->value; else - os << date_t(i->value()).as_formatted_localtime(fmt); - if (newline) - os << '\n'; - + { + I(name == date_cert_name); + os << date_t(i->value()).as_formatted_localtime(date_fmt); + } + first = false; } } } -static void -log_date_certs(vector const & certs, ostream & os, string const & fmt, - char const * label, bool multiline) -{ - log_date_certs(certs, os, fmt, label, label, multiline, true); -} - -static void -log_date_certs(vector const & certs, ostream & os, string const & fmt) -{ - log_date_certs(certs, os, fmt, " ", ",", false, false); -} - enum log_direction { log_forward, log_reverse }; struct rev_cmp @@ -919,6 +713,7 @@ CMD(log, "log", "", CMD_REF(informative) } cert_name const author_name(author_cert_name); + cert_name const date_name(date_cert_name); cert_name const branch_name(branch_cert_name); cert_name const tag_name(tag_cert_name); cert_name const changelog_name(changelog_cert_name); @@ -1037,49 +832,32 @@ CMD(log, "log", "", CMD_REF(informative) out << rid; log_certs(certs, out, author_name); if (app.opts.no_graph) - log_date_certs(certs, out, date_fmt); + log_certs(certs, out, date_name, date_fmt); else { out << '\n'; - log_date_certs(certs, out, date_fmt, "", "", false, false); + log_certs(certs, out, date_name, date_fmt); } log_certs(certs, out, branch_name); out << '\n'; } else { - out << string(65, '-') << '\n'; - out << _("Revision: ") << rid << '\n'; + utf8 header; + revision_header(rid, rev, certs, header); - changes_summary csum; + external header_external; + utf8_to_system_best_effort(header, header_external); + out << header_external; - set ancestors; - - for (edge_map::const_iterator e = rev.edges.begin(); - e != rev.edges.end(); ++e) + if (!app.opts.no_files) { - ancestors.insert(edge_old_revision(e)); - csum.add_change_set(edge_changes(e)); + utf8 summary; + revision_summary(rev, summary); + external summary_external; + utf8_to_system_best_effort(summary, summary_external); + out << summary_external; } - - for (set::const_iterator anc = ancestors.begin(); - anc != ancestors.end(); ++anc) - out << _("Ancestor: ") << *anc << '\n'; - - log_certs(certs, out, author_name, _("Author: "), false); - log_date_certs(certs, out, date_fmt, _("Date: "), false); - log_certs(certs, out, branch_name, _("Branch: "), false); - log_certs(certs, out, tag_name, _("Tag: "), false); - - if (!app.opts.no_files && !csum.cs.empty()) - { - out << '\n'; - csum.print(out, 70); - out << '\n'; - } - - log_certs(certs, out, changelog_name, _("ChangeLog: "), true); - log_certs(certs, out, comment_name, _("Comments: "), true); } if (app.opts.diffs) ============================================================ --- cmd_ws_commit.cc 0aa51a85aef50271b6755e53723ac9e94e49d189 +++ cmd_ws_commit.cc 5d0a6628314c487f2f0854257abcb9e396a1635b @@ -69,28 +69,29 @@ get_log_message_interactively(lua_hooks string & author, date_t & date, branch_name & branch, utf8 & log_message) { - external instructions( + utf8 instructions( _("Ensure the values for Author, Date and Branch are correct, then enter\n" "a description of this change following the Changelog line. Any other\n" "modifications to the lines below or to the summary of changes will\n" "cause the commit to fail.\n")); + utf8 changelog; + work.read_user_log(changelog); + + string text = changelog(); + if (!text.empty() && text[text.length()-1] != '\n') + { + text += '\n'; + changelog = utf8(text, origin::user); + } + utf8 header; - utf8 message; utf8 summary; - revision_header(rid, rev, author, date, branch, header); - work.read_user_log(message); + revision_header(rid, rev, author, date, branch, changelog, header); revision_summary(rev, summary); - string text = message(); - if (text.empty() || text.substr(text.length()-1) != "\n") - { - text += "\n"; - message = utf8(text, origin::user); - } - - utf8 full_message(instructions() + header() + message() + summary(), origin::internal); + utf8 full_message(instructions() + header() + summary(), origin::internal); external input_message; external output_message; @@ -654,10 +655,6 @@ CMD(status, "status", "", CMD_REF(inform if (!app.lua.hook_get_author(app.opts.branch, key, author)) author = key.official_name(); - utf8 header; - utf8 message; - utf8 summary; - calculate_ident(rev, rid); set old_branches; @@ -671,31 +668,30 @@ CMD(status, "status", "", CMD_REF(inform cout << _("New Branch: ") << app.opts.branch << "\n\n"; } - revision_header(rid, rev, author, date_t::now(), app.opts.branch, header); + utf8 changelog; + work.read_user_log(changelog); - work.read_user_log(message); - - string text = message(); - if (text.empty() || text.substr(text.length()-1) != "\n") + string text = changelog(); + if (!text.empty() && text[text.length()-1] != '\n') { - text += "\n"; - message = utf8(text, origin::user); + text += '\n'; + changelog = utf8(text, origin::user); } + utf8 header; + utf8 summary; + + revision_header(rid, rev, author, date_t::now(), app.opts.branch, changelog, header); revision_summary(rev, summary); external header_external; - external message_external; external summary_external; utf8_to_system_best_effort(header, header_external); - utf8_to_system_best_effort(message, message_external); utf8_to_system_best_effort(summary, summary_external); cout << header_external - << message_external - << summary_external - << '\n'; + << summary_external; } CMD(checkout, "checkout", "co", CMD_REF(tree), N_("[DIRECTORY]"), ============================================================ --- rev_output.cc d3979e2e706aaa0fee3947ae424b9e9595460fed +++ rev_output.cc 8cb1fadbcd79aab23bf95c26aec3390f4fa950d6 @@ -11,28 +11,52 @@ #include #include #include +#include +#include "cert.hh" #include "cset.hh" #include "dates.hh" +#include "project.hh" #include "rev_output.hh" #include "revision.hh" using std::map; +using std::ostringstream; using std::pair; using std::set; using std::string; -using std::ostringstream; +using std::vector; void revision_header(revision_id const rid, revision_t const & rev, string const & author, date_t const date, - branch_name const & branch, utf8 & header) + branch_name const & branch, utf8 const & changelog, + utf8 & header) { + vector certs; + key_id empty_key; + certs.push_back(cert(rid, author_cert_name, + cert_value(author, origin::user), empty_key)); + certs.push_back(cert(rid, date_cert_name, + cert_value(date.as_iso_8601_extended(), origin::user), + empty_key)); + certs.push_back(cert(rid, branch_cert_name, + cert_value(branch(), origin::user), empty_key)); + if (!changelog().empty()) + certs.push_back(cert(rid, changelog_cert_name, + cert_value(changelog(), origin::user), empty_key)); + + revision_header(rid, rev, certs, header); +} + +void +revision_header(revision_id const rid, revision_t const & rev, + vector const & certs, utf8 & header) +{ ostringstream out; - int const width = 70; - out << string(width, '-') << '\n' - << _("Revision: ") << rid << _(" (uncommitted)") << '\n'; + out << string(70, '-') << '\n' + << _("Revision: ") << rid << '\n'; for (edge_map::const_iterator i = rev.edges.begin(); i != rev.edges.end(); ++i) { @@ -40,11 +64,45 @@ revision_header(revision_id const rid, r out << _("Parent: ") << parent << '\n'; } - out << _("Author: ") << author << '\n' - << _("Date: ") << date << '\n' - << _("Branch: ") << branch << '\n' - << _("ChangeLog: ") << "\n\n"; + cert_name const author(author_cert_name); + cert_name const date(date_cert_name); + cert_name const branch(branch_cert_name); + cert_name const tag(tag_cert_name); + cert_name const changelog(changelog_cert_name); + cert_name const comment(comment_cert_name); + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == author) + out << _("Author: ") << i->value << '\n'; + + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == date) + out << _("Date: ") << i->value << '\n'; // FIXME: date formats + + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == branch) + out << _("Branch: ") << i->value << '\n'; + + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == tag) + out << _("Tag: ") << i->value << '\n'; + + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == changelog) + { + out << _("ChangeLog: ") << "\n\n" << i->value << '\n'; + if (!i->value().empty() && i->value()[i->value().length()-1] != '\n') + out << '\n'; + } + + for (vector::const_iterator i = certs.begin(); i != certs.end(); ++i) + if (i->name == comment) + { + out << _("Comments: ") << "\n\n" << i->value << '\n'; + if (!i->value().empty() && i->value()[i->value().length()-1] != '\n') + out << '\n'; + } + header = utf8(out.str(), origin::internal); } @@ -64,8 +122,6 @@ revision_summary(revision_t const & rev, revision_id parent = edge_old_revision(*i); cset const & cs = edge_changes(*i); - out << '\n'; - // A colon at the end of this string looked nicer, but it made // double-click copying from terminals annoying. if (!null_id(parent)) @@ -113,6 +169,8 @@ revision_summary(revision_t const & rev, i = cs.attrs_cleared.begin(); i != cs.attrs_cleared.end(); ++i) out << _(" attr on ") << i->first << '\n' << _(" unset ") << i->second << '\n'; + + out << '\n'; } summary = utf8(out.str(), origin::internal); } ============================================================ --- rev_output.hh a81f8b7801fe5adceb0b988fe79f9af7dc85ae8c +++ rev_output.hh 04094228d1f6e4828d139f41be4ce6eb6b08b593 @@ -14,13 +14,19 @@ struct date_t; #include "vocab.hh" struct date_t; +struct cert; void revision_header(revision_id const rid, revision_t const & rev, std::string const & author, date_t const date, - branch_name const & branch, utf8 & header); + branch_name const & branch, utf8 const & changelog, + utf8 & header); void +revision_header(revision_id const rid, revision_t const & rev, + std::vector const & certs, utf8 & header); + +void revision_summary(revision_t const & rev, utf8 & summary); #endif // header guard