# # # add_file "asciik.hh" # content [36c281faea3cd6c21ecff24747d138a03eb88393] # # patch "ChangeLog" # from [9f706ce8e676326f35760bbc8dc9d290dcfb4725] # to [4be837d91418af1cd05842def247838079db4b4a] # # patch "Makefile.am" # from [500f7d607b4f420e72520115366f43bd96c59f0e] # to [8a2970c1e088add1fbe734467c1962d5d9928f46] # # patch "asciik.cc" # from [28b20f53816beee894500a47e22faabe0085a9be] # to [ffa88051ab21603eb1c334cee164c2bcf6d31987] # # set "asciik.hh" # attr "mtn:execute" # value "true" # ============================================================ --- asciik.hh 36c281faea3cd6c21ecff24747d138a03eb88393 +++ asciik.hh 36c281faea3cd6c21ecff24747d138a03eb88393 @@ -0,0 +1,24 @@ +#ifndef __ASCIIK_HH__ +#define __ASCIIK_HH__ + +#include +#include + +#include "revision.hh" + +class asciik +{ +public: + asciik(); + // Prints an ASCII-k chunk using the given revisions. + void print(const revision_id & rev, const std::set & parents, const string & annotation); + //TODO: cambiare set-parents to vector-next +private: + void links_cross(const std::set > & links, std::set & crosses) const; + void draw(const size_t curr_items, const size_t next_items, const size_t curr_loc, const std::set > & links, const std::set & curr_ghosts, const string & annotation) const; + bool try_draw(const std::vector & next_row, const size_t curr_loc, const std::set & parents, const string & annotation) const; + // internal state + std::vector curr_row; +}; + +#endif ============================================================ --- ChangeLog 9f706ce8e676326f35760bbc8dc9d290dcfb4725 +++ ChangeLog 4be837d91418af1cd05842def247838079db4b4a @@ -1,3 +1,7 @@ +2007-02-09 Lapo Luchini + + * asciik.{cc,hh}: asciik is now a proper class with internal state. + 2007-02-08 Zack Weinberg * configure.ac: Stick some goo in config.status to kill @@ -52,10 +56,6 @@ 2007-02-07 Derek Scherger - - * vocab_macros.hh: changed operator!=() to actually use inner ==. - 2007-02-07 Daniel Carosone * tests/db_kill_rev_and_recommit/__driver__.lua/: add a test @@ -124,10 +124,6 @@ 2007-02-07 Derek Scherger - - * vocab_macros.hh: added some missing operator!=(). - 2007-02-07 Matthew Gregan * win32/os_strerror.c (os_strerror): Clean up string handling. ============================================================ --- Makefile.am 500f7d607b4f420e72520115366f43bd96c59f0e +++ Makefile.am 8a2970c1e088add1fbe734467c1962d5d9928f46 @@ -82,7 +82,7 @@ MOST_SOURCES = \ option.cc option.hh options.cc options.hh options_list.hh \ i18n.h parallel_iter.hh safe_map.hh pch.hh \ \ - asciik.cc + asciik.cc asciik.hh NETXX_SOURCES = \ netxx/accept.cxx netxx/accept.h netxx/address.cxx \ ============================================================ --- asciik.cc 28b20f53816beee894500a47e22faabe0085a9be +++ asciik.cc ffa88051ab21603eb1c334cee164c2bcf6d31987 @@ -9,25 +9,6 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. -#include -#include -#include -#include -#include -#include - -#include "cmd.hh" -#include "revision.hh" - -using std::cout; -using std::insert_iterator; -using std::max; -using std::min; -using std::ostream_iterator; -using std::pair; -using std::set; -using std::vector; - /* BUGS: @@ -127,21 +108,35 @@ Loop: Having found a layout that works, we draw lines connecting things! Yay. */ -//namespace asciik { } +#include +#include +#include +//#include +// tuples are faster than std::pair on copy constructors, but we're only using +// std::pair so it probably doesn't matter much -/** - * Prints an ASCII-k chunk using the given revisions. - */ -//void asciik::print(set ids) { -// database::get_revision_parents(revision_id const & id, set & parents) -// for (iterator id = ids.begin(); id != ids.end(); ++id) -// os << "Work on: " << id << "\n"; -//} +#include "asciik.hh" +#include "cmd.hh" +using std::cout; +using std::insert_iterator; +using std::max; +using std::min; +using std::ostream_iterator; +using std::pair; +using std::set; +using std::vector; + static revision_id ghost; // valid but empty revision_id to be used as ghost value -void links_cross(const set > & links, set & crosses) +asciik::asciik() { +} + +void +asciik::links_cross(const set > & links, + set & crosses) const +{ for (set >::const_iterator link = links.begin(); link != links.end(); ++link) { @@ -153,9 +148,10 @@ void links_cross(const set > & links, - const set & curr_ghosts, const string & annotation) + const set & curr_ghosts, const string & annotation) const { string line(curr_items * 2 - 1, ' '); string interline(max(curr_items, next_items) * 2 - 1, ' '); @@ -179,7 +175,7 @@ void draw(const size_t curr_items, const interline[2 * i] = '|'; else { if (j < i) { - // | .---o + // | ·---o // |/| | | // 0 1 2 3 // j i @@ -190,7 +186,7 @@ void draw(const size_t curr_items, const dot = start - 1; interline[dot - 1] = '/'; } else { // i < j - // o---. + // o---· // | | |\| // 0 1 2 3 // i j @@ -209,22 +205,22 @@ void draw(const size_t curr_items, const } // add any dots (must do this in a second pass, so that if there are // cases like: - // | .-----.-o + // | ·-----·-o // |/| | |/| - // where we want to make sure the second dot overwrites the first --. + // where we want to make sure the second dot overwrites the first --· for (set::const_iterator dot = dots.begin(); dot != dots.end(); ++dot) - line[*dot] = '·'; - // and add the main attraction (may overwrite a "."). + line[*dot] = '·'; //TODO: what about this special char? should it be UTF-8? + // and add the main attraction (may overwrite a '·'). line[curr_loc * 2] = 'o'; cout << line << " " << annotation << '\n'; cout << interline << '\n'; } -bool try_draw(const vector & curr_row, - const vector & next_row, const size_t curr_loc, - const set & parents) +bool +asciik::try_draw(const vector & next_row, const size_t curr_loc, + const set & parents, const string & annotation) const { size_t curr_items = curr_row.size(); size_t next_items = next_row.size(); @@ -280,10 +276,52 @@ bool try_draw(const vector set > links(preservation_links); copy(parent_links.begin(), parent_links.end(), insert_iterator > >(links, links.begin())); - draw(curr_items, next_items, curr_loc, links, curr_ghosts, - /*annotation*/ idx(curr_row, curr_loc).inner()()); + draw(curr_items, next_items, curr_loc, links, curr_ghosts, annotation); + return true; +} - return true; +void +asciik::print(const revision_id & rev, const set & parents, + const string & annotation) +{ + if (find(curr_row.begin(), curr_row.end(), rev) == curr_row.end()) + curr_row.push_back(rev); + + //iterator_traits::iterator>::difference_type + size_t curr_loc = distance(curr_row.begin(), + find(curr_row.begin(), curr_row.end(), rev)); + I(curr_loc < curr_row.size()); // as it is surely found + + set new_revs; + for (set::const_iterator parent = parents.begin(); + parent != parents.end(); ++parent) + if (find(curr_row.begin(), curr_row.end(), *parent) == curr_row.end()) + new_revs.insert(*parent); + + vector next_row(curr_row); + next_row.insert( + next_row.erase(next_row.begin() + curr_loc), + new_revs.begin(), new_revs.end()); + + // now next_row contains exactly the revisions it needs to, except that no + // ghost handling has been done. + vector no_ghost(next_row); + vector::iterator first_ghost = find(no_ghost.begin(), + no_ghost.end(), ghost); + if (first_ghost != no_ghost.end()) + no_ghost.erase(first_ghost); + + if (try_draw(no_ghost, curr_loc, parents, annotation)) + curr_row = no_ghost; + else if (try_draw(next_row, curr_loc, parents, annotation)) + curr_row = next_row; + else if (new_revs.size() == 0) { // this line has disappeared + vector extra_ghost(next_row); + extra_ghost.insert(curr_row.begin() + curr_loc, ghost); + if (!try_draw(extra_ghost, curr_loc, parents, annotation)) + I(false); + curr_row = extra_ghost; + } } CMD(asciik, N_("tree"), N_("SELECTOR"), @@ -301,6 +339,7 @@ CMD(asciik, N_("tree"), N_("SELECTOR"), selectors::selector_type ty = selectors::sel_ident; selectors::complete_selector("", sels, ty, completions, app); + asciik graph; set revs; for (set::const_iterator i = completions.begin(); i != completions.end(); ++i) @@ -317,48 +356,9 @@ CMD(asciik, N_("tree"), N_("SELECTOR"), for (vector::const_iterator rev = sorted.begin(); rev != sorted.end(); ++rev) { - // print row - - if (find(curr_row.begin(), curr_row.end(), *rev) == curr_row.end()) - curr_row.push_back(*rev); - - //iterator_traits::iterator>::difference_type - size_t curr_loc = distance(curr_row.begin(), - find(curr_row.begin(), curr_row.end(), *rev)); - //assert(curr_loc < size()); as it is surely found - set parents; app.db.get_revision_parents(*rev, parents); parents.erase(ghost); // remove the fake parent that root nodes have - set new_revs; - for (set::const_iterator parent = parents.begin(); - parent != parents.end(); ++parent) - if (find(curr_row.begin(), curr_row.end(), *parent) == curr_row.end()) - new_revs.insert(*parent); - - vector next_row(curr_row); - next_row.insert( - next_row.erase(next_row.begin() + curr_loc), - new_revs.begin(), new_revs.end()); - - // now next_row contains exactly the revisions it needs to, except that no - // ghost handling has been done. - vector no_ghost(next_row); - vector::iterator first_ghost = find(no_ghost.begin(), - no_ghost.end(), ghost); - if (first_ghost != no_ghost.end()) - no_ghost.erase(first_ghost); - - if (try_draw(curr_row, no_ghost, curr_loc, parents)) - curr_row = no_ghost; - else if (try_draw(curr_row, next_row, curr_loc, parents)) - curr_row = next_row; - else if (new_revs.size() == 0) { // this line has disappeared - vector extra_ghost(next_row); - extra_ghost.insert(curr_row.begin() + curr_loc, ghost); - if (!try_draw(curr_row, extra_ghost, curr_loc, parents)) - I(false); - curr_row = extra_ghost; - } + graph.print(*rev, parents, rev->inner()()); } }