#include "vdm/rules/collision.hpp" #include #include namespace vdm::rules { namespace { // Split on the last '.', unless it's a leading dot (a dotfile like ".gitignore" has no // extension by this convention — matches sanitize_filename's own treatment). Returns // {stem, ext} where `ext` includes the leading '.' when present. std::pair split_stem_ext(std::string_view name) { auto dot = name.rfind('.'); if (dot == std::string_view::npos || dot == 0) return {name, {}}; return {name.substr(0, dot), name.substr(dot)}; } } // namespace std::string resolve_collision(std::string_view desired, const std::function &exists, CollisionPolicy policy, int max_attempts) { if (policy == CollisionPolicy::overwrite) return std::string(desired); if (!exists || !exists(desired)) return std::string(desired); auto [stem, ext] = split_stem_ext(desired); std::string candidate; for (int n = 1; n <= max_attempts; ++n) { candidate = std::string(stem) + " (" + std::to_string(n) + ")" + std::string(ext); if (!exists(candidate)) return candidate; } return candidate; // still colliding; see the header comment on why this isn't hidden } } // namespace vdm::rules