# # # patch "selectors.cc" # from [4411aba2df0446609aaeaca65eaa9fd306ceb7ee] # to [330f8c765a5cfc528c04041629cb79b6222adaa4] # ============================================================ --- selectors.cc 4411aba2df0446609aaeaca65eaa9fd306ceb7ee +++ selectors.cc 330f8c765a5cfc528c04041629cb79b6222adaa4 @@ -17,6 +17,7 @@ #include "globish.hh" #include "cmd.hh" #include "work.hh" +#include "revision.hh" #include #include @@ -29,6 +30,12 @@ using std::inserter; using std::set_intersection; using std::inserter; +enum meta_selector_type + { + meta_sel_heads_of, + meta_sel_unknown + }; + enum selector_type { sel_author, @@ -46,17 +53,48 @@ typedef vector > selector_list; +typedef struct +{ + meta_selector_type meta_type; + selector_list selections; +} selector_data; static void +decode_meta_selector(project_t & project, + options const & opts, + lua_hooks & lua, + meta_selector_type & meta_type, + string & sel) +{ + L(FL("decoding possible meta selector '%s'") % sel); + + meta_selector_type tmp = meta_sel_unknown; + + if (sel.size() >= 2 && sel[1] == ':') + { + switch (sel[0]) + { + case 'H': + tmp = meta_sel_heads_of; + break; + default: + break; + } + } + + if (tmp != meta_sel_unknown) + sel.erase(0,2); + + meta_type = tmp; +} + +static void decode_selector(project_t & project, options const & opts, lua_hooks & lua, - string const & orig_sel, selector_type & type, string & sel) { - sel = orig_sel; - L(FL("decoding selector '%s'") % sel); string tmp; @@ -201,22 +239,26 @@ parse_selector(project_t & project, parse_selector(project_t & project, options const & opts, lua_hooks & lua, - string const & str, selector_list & sels) + string const & str, selector_data & seldata) { - sels.clear(); + seldata.meta_type = meta_sel_unknown; + seldata.selections.clear(); // this rule should always be enabled, even if the user specifies // --norc: if you provide a revision id, you get a revision id. if (str.find_first_not_of(constants::legal_id_bytes) == string::npos && str.size() == constants::idlen) { - sels.push_back(make_pair(sel_ident, str)); + seldata.selections.push_back(make_pair(sel_ident, str)); } else { + string tmp = str; + decode_meta_selector(project, opts, lua, seldata.meta_type, tmp); + typedef boost::tokenizer > tokenizer; boost::escaped_list_separator slash("\\", "/", ""); - tokenizer tokens(str, slash); + tokenizer tokens(tmp, slash); vector selector_strings; copy(tokens.begin(), tokens.end(), back_inserter(selector_strings)); @@ -224,11 +266,11 @@ parse_selector(project_t & project, for (vector::const_iterator i = selector_strings.begin(); i != selector_strings.end(); ++i) { - string sel; + string sel = *i; selector_type type = sel_unknown; - decode_selector(project, opts, lua, *i, type, sel); - sels.push_back(make_pair(type, sel)); + decode_selector(project, opts, lua, type, sel); + seldata.selections.push_back(make_pair(type, sel)); } } } @@ -325,20 +367,20 @@ complete_selector(project_t & project, static void complete_selector(project_t & project, - selector_list const & limit, + selector_data const & limit, set & completions) { - if (limit.empty()) // all the ids in the database + if (limit.selections.empty()) // all the ids in the database { project.db.complete("", completions); return; } - selector_list::const_iterator i = limit.begin(); + selector_list::const_iterator i = limit.selections.begin(); complete_one_selector(project, i->first, i->second, completions); i++; - while (i != limit.end()) + while (i != limit.selections.end()) { set candidates; set intersection; @@ -352,6 +394,15 @@ complete_selector(project_t & project, completions = intersection; i++; } + + switch(limit.meta_type) + { + case meta_sel_heads_of: + erase_ancestors(project.db, completions); + break; + default: + break; + } } void @@ -360,22 +411,22 @@ complete(options const & opts, lua_hooks string const & str, set & completions) { - selector_list sels; - parse_selector(project, opts, lua, str, sels); + selector_data seldata; + parse_selector(project, opts, lua, str, seldata); // avoid logging if there's no expansion to be done - if (sels.size() == 1 - && sels[0].first == sel_ident - && sels[0].second.size() == constants::idlen) + if (seldata.selections.size() == 1 + && seldata.selections[0].first == sel_ident + && seldata.selections[0].second.size() == constants::idlen) { - completions.insert(revision_id(sels[0].second)); + completions.insert(revision_id(seldata.selections[0].second)); N(project.db.revision_exists(*completions.begin()), F("no such revision '%s'") % *completions.begin()); return; } P(F("expanding selection '%s'") % str); - complete_selector(project, sels, completions); + complete_selector(project, seldata, completions); N(completions.size() != 0, F("no match for selection '%s'") % str); @@ -415,19 +466,19 @@ expand_selector(options const & opts, lu string const & str, set & completions) { - selector_list sels; - parse_selector(project, opts, lua, str, sels); + selector_data seldata; + parse_selector(project, opts, lua, str, seldata); // avoid logging if there's no expansion to be done - if (sels.size() == 1 - && sels[0].first == sel_ident - && sels[0].second.size() == constants::idlen) + if (seldata.selections.size() == 1 + && seldata.selections[0].first == sel_ident + && seldata.selections[0].second.size() == constants::idlen) { - completions.insert(revision_id(sels[0].second)); + completions.insert(revision_id(seldata.selections[0].second)); return; } - complete_selector(project, sels, completions); + complete_selector(project, seldata, completions); } void