# # # patch "cmd_diff_log.cc" # from [ad4d4cafa86651204fdf5031adb737e95f80c4da] # to [67eb9f819442e03d6ebe74beb1580dd0de7414f1] # # patch "cmd_list.cc" # from [6eea78f760ce2906a93befd417d81c6989451ad1] # to [3cfcbe4d2f8d5073d644e61902e8e5f159168ddf] # # patch "cmd_ws_commit.cc" # from [8321ee742a65e2ebaf58c328bdf6bdda11c8f21c] # to [39994676c87c70690e8e9a0254d647d317ad3381] # # patch "paths.cc" # from [9af29f3e1c0564f9a9ccf0be3468a71de8a729fa] # to [739c98e9f973a674309edcab5f596aec4c130992] # # patch "paths.hh" # from [f37bdd30f00c3448268723a701924ca5b9450891] # to [970ca28cfe9fc3c2efb3d230a2f9d043357195fe] # ============================================================ --- cmd_diff_log.cc ad4d4cafa86651204fdf5031adb737e95f80c4da +++ cmd_diff_log.cc 67eb9f819442e03d6ebe74beb1580dd0de7414f1 @@ -101,9 +101,8 @@ print_indented_set(ostream & os, for (set::const_iterator i = s.begin(); i != s.end(); i++) { - string str = lexical_cast(*i); - if (str.empty()) - str = "."; // project root + string str = i->as_relative(); + if (cols > 8 && cols + str.size() + 1 >= max_cols) { cols = 8; @@ -131,8 +130,8 @@ changes_summary::print(ostream & os, siz for (map::const_iterator i = cs.nodes_renamed.begin(); i != cs.nodes_renamed.end(); i++) - os << " " << i->first - << " to " << i->second << '\n'; + os << " " << i->first.as_relative() + << " to " << i->second.as_relative() << '\n'; } if (! cs.files_added.empty()) ============================================================ --- cmd_list.cc 6eea78f760ce2906a93befd417d81c6989451ad1 +++ cmd_list.cc 3cfcbe4d2f8d5073d644e61902e8e5f159168ddf @@ -347,24 +347,22 @@ static void } static void -print_paths(path_set const & paths) +print_paths(set const & paths) { - vector relative_paths; + set formatted; - for (path_set::const_iterator i = paths.begin(); i != paths.end(); ++i) + for (set::const_iterator i = paths.begin(); i != paths.end(); ++i) { - relative_paths.push_back(make_relative(*i)); + formatted.insert(i->as_relative()); } - sort(relative_paths.begin(), relative_paths.end()); + //sort(formatted.begin(), formatted.end()); - for (vector::const_iterator sp = relative_paths.begin(); - sp != relative_paths.end(); sp++) - cout << file_path(*sp).as_external() << "\n"; + copy(formatted.begin(), formatted.end(), + ostream_iterator(cout, "\n")); + } -static void -ls_known(app_state & app, vector const & args) CMD(known, "known", "", CMD_REF(list), "", N_("Lists workspace files that belong to the current branch"), "", @@ -382,7 +380,7 @@ CMD(known, "known", "", CMD_REF(list), " new_roster, app); // to be printed sorted - vector print_paths; + set known; node_map const & nodes = new_roster.all_nodes(); for (node_map::const_iterator i = nodes.begin(); @@ -390,19 +388,15 @@ CMD(known, "known", "", CMD_REF(list), " { node_id nid = i->first; - if (!new_roster.is_root(nid) - && mask.includes(new_roster, nid)) + if (mask.includes(new_roster, nid)) { file_path p; new_roster.get_name(nid, p); - print_paths.push_back(p); + known.insert(p); } } - sort(print_paths.begin(), print_paths.end()); - copy(print_paths.begin(), print_paths.end(), - ostream_iterator(cout, "\n")); - print_paths(paths); + print_paths(known); } CMD(unknown, "unknown", "ignored", CMD_REF(list), "", @@ -425,17 +419,12 @@ CMD(unknown, "unknown", "ignored", CMD_R utf8 const & realname = execid[execid.size() - 1]; if (realname() == "ignored") - copy(ignored.begin(), ignored.end(), - ostream_iterator(cout, "\n")); - if (want_ignored) print_paths(ignored); else { I(realname() == "unknown"); - copy(unknown.begin(), unknown.end(), - ostream_iterator(cout, "\n")); + print_paths(unknown); } - print_paths(unknown); } CMD(missing, "missing", "", CMD_REF(list), "", @@ -454,8 +443,6 @@ CMD(missing, "missing", "", CMD_REF(list set missing; app.work.find_missing(current_roster_shape, mask, missing); - copy(missing.begin(), missing.end(), - ostream_iterator(cout, "\n")); print_paths(missing); } @@ -485,7 +472,7 @@ CMD(changed, "changed", "", CMD_REF(list make_restricted_revision(parents, new_roster, mask, rrev); // to be printed sorted, with duplicates removed - set print_paths; + set changed; for (edge_map::const_iterator i = rrev.edges.begin(); i != rrev.edges.end(); i++) @@ -504,13 +491,11 @@ CMD(changed, "changed", "", CMD_REF(list new_roster.get_name(*i, p); else old_roster.get_name(*i, p); - print_paths.insert(p); + changed.insert(p); } } - copy(print_paths.begin(), print_paths.end(), - ostream_iterator(cout, "\n")); - print_paths(paths); + print_paths(changed); } namespace ============================================================ --- cmd_ws_commit.cc 8321ee742a65e2ebaf58c328bdf6bdda11c8f21c +++ cmd_ws_commit.cc 39994676c87c70690e8e9a0254d647d317ad3381 @@ -56,39 +56,45 @@ revision_summary(revision_t const & rev, for (set::const_iterator i = cs.nodes_deleted.begin(); i != cs.nodes_deleted.end(); ++i) - out += (F(" dropped %s") % *i).str() += '\n'; + out += (F(" dropped %s") + % i->as_relative()).str() += '\n'; for (map::const_iterator i = cs.nodes_renamed.begin(); i != cs.nodes_renamed.end(); ++i) out += (F(" renamed %s\n" - " to %s") % i->first % i->second).str() += '\n'; + " to %s") + % i->first.as_relative() + % i->second.as_relative()).str() += '\n'; for (set::const_iterator i = cs.dirs_added.begin(); i != cs.dirs_added.end(); ++i) - out += (F(" added %s") % *i).str() += '\n'; + out += (F(" added %s") % i->as_relative()).str() += '\n'; for (map::const_iterator i = cs.files_added.begin(); i != cs.files_added.end(); ++i) - out += (F(" added %s") % i->first).str() += '\n'; + out += (F(" added %s") + % i->first.as_relative()).str() += '\n'; for (map >::const_iterator i = cs.deltas_applied.begin(); i != cs.deltas_applied.end(); ++i) - out += (F(" patched %s") % (i->first)).str() += '\n'; + out += (F(" patched %s") + % (i->first.as_relative())).str() += '\n'; for (map, attr_value >::const_iterator i = cs.attrs_set.begin(); i != cs.attrs_set.end(); ++i) out += (F(" attr on %s\n" " attr %s\n" " value %s") - % (i->first.first) % (i->first.second) % (i->second) - ).str() += "\n"; + % (i->first.first.as_relative()) + % (i->first.second) % (i->second)).str() += "\n"; for (set >::const_iterator i = cs.attrs_cleared.begin(); i != cs.attrs_cleared.end(); ++i) out += (F(" unset on %s\n" " attr %s") - % (i->first) % (i->second)).str() += "\n"; + % (i->first.as_relative()) + % (i->second)).str() += "\n"; } summary = utf8(out); } ============================================================ --- paths.cc 9af29f3e1c0564f9a9ccf0be3468a71de8a729fa +++ paths.cc 739c98e9f973a674309edcab5f596aec4c130992 @@ -65,7 +65,7 @@ struct access_tracker // paths to use in interpreting paths from various sources, // conceptually: -// working_root / initial_rel_path == initial_abs_path +// workspace_root / initial_rel_path == initial_abs_path // initial_abs_path is for interpreting relative system_path's static access_tracker initial_abs_path; @@ -595,48 +595,6 @@ file_path::dirname_basename(file_path & } } -split_path -make_relative(split_path const & sp) -{ - I(initial_rel_path.initialized); - fs::path base = initial_rel_path.get_but_unused(); - file_path fp = file_path_internal(base.string()); - split_path bp; - fp.split(bp); - - split_path relative; - static const path_component dot("."); - static const path_component dotdot(".."); - - relative.push_back(the_null_component); - - split_path::const_iterator i = sp.begin(); - split_path::const_iterator j = bp.begin(); - - while (i != sp.end() && j != bp.end() && *i == *j) - { - i++; - j++; - } - while (j != bp.end()) - { - relative.push_back(dotdot); - j++; - } - - if (relative.size() == 1) - relative.push_back(dot); - - while (i != sp.end()) - { - relative.push_back(*i); - i++; - } - - return relative; -} - - // count the number of /-separated components of the path. unsigned int file_path::depth() const @@ -674,6 +632,82 @@ any_path::as_external() const #endif } +string +file_path::as_relative() const +{ + I(initial_rel_path.initialized); + + string base = initial_rel_path.get_but_unused(); + string::size_type prefix = 0; + + while (prefix < data.length() && + prefix < base.length() && + data[prefix] == base[prefix]) + ++prefix; + + if (prefix < data.length() && prefix < base.length()) + { + // possible match, back up to the last / character + while (prefix > 0 && (base[prefix] != '/' || data[prefix] != '/')) + --prefix; + } + else if (prefix >= data.length() && prefix < base.length()) + { + // base path below this path + while (prefix > 0 && base[prefix] != '/') + --prefix; + } + else if (prefix < data.length() && prefix >= base.length()) + { + // this path below base path + while (prefix > 0 && data[prefix] != '/') + --prefix; + } + // else exact match of entire string + + string::size_type base_suffix, data_suffix; + + // normalize suffixes so they never start with a / character + + if (prefix < base.length() && base[prefix] == '/') + base_suffix = prefix+1; + else + base_suffix = prefix; + + if (prefix < data.length() && data[prefix] == '/') + data_suffix = prefix+1; + else + data_suffix = prefix; + + // up from the base path's directories + + string relative; + + if (base_suffix < base.length()) relative.append(".."); + + for (string::size_type i = base_suffix; i < base.length(); i++) + if (base[i] == '/') + relative.append("/.."); + + // down into this path's directories + + if (data_suffix < data.length()) + { + if (!relative.empty()) + relative.append("/"); + relative.append(data.substr(data_suffix)); + } + + // special case for the root directory + + if (relative.empty()) + relative.append("."); + + // FIXME: this should probably return a string in the user's charset + return relative; +} + + /////////////////////////////////////////////////////////////////////////// // writing out paths /////////////////////////////////////////////////////////////////////////// ============================================================ --- paths.hh f37bdd30f00c3448268723a701924ca5b9450891 +++ paths.hh 970ca28cfe9fc3c2efb3d230a2f9d043357195fe @@ -203,6 +203,8 @@ public: // does dirname() and basename() at the same time, for efficiency void dirname_basename(file_path &, path_component &) const; + std::string as_relative() const; + // returns the number of /-separated components of the path. // The empty path has depth zero. unsigned int depth() const;