diff --git a/src/prodir/cpp/tree_structurer.cpp b/src/prodir/cpp/tree_structurer.cpp index fe31f25..6a961d9 100644 --- a/src/prodir/cpp/tree_structurer.cpp +++ b/src/prodir/cpp/tree_structurer.cpp @@ -123,7 +123,6 @@ std::vector TreeStructurer::get_filtered_paths(const fs::path& start) std::vector TreeStructurer::get_directory_structure(const std::string& startpath) { std::vector result; - // Normalize the input path by removing ./ or .\ prefix if present std::string normalized_path = startpath; if (normalized_path.size() >= 2 && (normalized_path.substr(0, 2) == ".\\" || normalized_path.substr(0, 2) == "./")) { @@ -140,144 +139,70 @@ std::vector TreeStructurer::get_directory_structure(const std::stri throw std::runtime_error("Path is not a directory: " + start.string()); } - // Start with the root node - std::string root_name = start.filename().string(); - result.push_back(root_name + "/"); + // Get all paths and sort them + std::vector paths; + std::map> dir_contents; - // First, collect all paths and organize them by their parent directories - std::map> dir_contents; - std::vector dir_paths; // To maintain order of directories - - // Add root directory - dir_contents["/"] = {}; - dir_paths.push_back("/"); - - // Collect files and directories - for (const auto& entry : fs::recursive_directory_iterator(start)) { - const auto& path = entry.path(); - std::string rel_path = get_relative_path(path, start); - - // Replace backslashes with forward slashes - std::replace(rel_path.begin(), rel_path.end(), '\\', '/'); - - // Skip if it should be ignored - bool should_skip = false; - for (const auto& component : path) { - if (should_ignore_dir(component.string())) { - should_skip = true; - break; - } - } - if (should_skip) continue; - + // First, collect all paths + for (const auto& entry : fs::directory_iterator(start)) { + fs::path path = entry.path(); if (entry.is_directory()) { - if (should_ignore_dir(path.filename().string())) { - continue; - } - - // Add directory to its parent - std::string parent_path = "/"; - size_t last_slash = rel_path.find_last_of('/'); - if (last_slash != std::string::npos) { - parent_path = rel_path.substr(0, last_slash); - if (parent_path.empty()) { - parent_path = "/"; + if (!should_ignore_dir(path.filename().string())) { + paths.push_back(path); + // Collect contents of this directory + for (const auto& subentry : fs::directory_iterator(path)) { + if (!should_ignore_file(subentry.path().filename().string()) && + !should_ignore_dir(subentry.path().filename().string())) { + dir_contents[path].push_back(subentry.path()); + } } } - - // Create parent directory entry if it doesn't exist - if (dir_contents.find(parent_path) == dir_contents.end()) { - dir_contents[parent_path] = {}; - dir_paths.push_back(parent_path); - } - - // Create directory entry - dir_contents[parent_path].push_back(path); - - // Create entry for this directory's contents - dir_contents[rel_path] = {}; - dir_paths.push_back(rel_path); } else { - if (should_ignore_file(path.filename().string())) { - continue; + if (!should_ignore_file(path.filename().string())) { + paths.push_back(path); } - - // Add file to its parent - std::string parent_path = "/"; - size_t last_slash = rel_path.find_last_of('/'); - if (last_slash != std::string::npos) { - parent_path = rel_path.substr(0, last_slash); - if (parent_path.empty()) { - parent_path = "/"; - } - } - - // Create parent directory entry if it doesn't exist - if (dir_contents.find(parent_path) == dir_contents.end()) { - dir_contents[parent_path] = {}; - dir_paths.push_back(parent_path); - } - - dir_contents[parent_path].push_back(path); } } - // Now create the tree structure - std::function&)> - build_tree = [&](const std::string& dir_path, const std::string& prefix, std::vector& is_last_stack) { - // Sort paths - directories first, then files - std::vector& paths = dir_contents[dir_path]; - std::sort(paths.begin(), paths.end(), [](const fs::path& a, const fs::path& b) { - bool a_is_dir = fs::is_directory(a); - bool b_is_dir = fs::is_directory(b); - if (a_is_dir != b_is_dir) { - return a_is_dir > b_is_dir; // Directories before files - } - return a.filename() < b.filename(); // Alphabetical order - }); + // Sort paths + std::sort(paths.begin(), paths.end()); + for (auto& [dir, contents] : dir_contents) { + std::sort(contents.begin(), contents.end()); + } + + // Add root directory + std::string root_name = start.filename().string(); + result.push_back(root_name + "/"); + + // Process each path + for (size_t i = 0; i < paths.size(); ++i) { + bool is_last = (i == paths.size() - 1); + std::string line = is_last ? "└── " : "├── "; - // Add entries for this directory - for (size_t i = 0; i < paths.size(); ++i) { - const auto& path = paths[i]; - bool is_last = (i == paths.size() - 1); - - // Build the line prefix - std::string line_prefix = prefix; - if (!prefix.empty()) { - line_prefix += is_last ? "└── " : "├── "; - } - - // Add the file/directory name - std::string name = path.filename().string(); - std::string line = line_prefix + name; - - if (fs::is_directory(path)) { - line += "/"; - } - - result.push_back(line); - - // If it's a directory, process its contents with updated prefix - if (fs::is_directory(path)) { - std::string rel_path = get_relative_path(path, start); - std::replace(rel_path.begin(), rel_path.end(), '\\', '/'); + std::string name = paths[i].filename().string(); + if (fs::is_directory(paths[i])) { + name += "/"; + } + line += name; + result.push_back(line); + + // If it's a directory, process its contents + if (fs::is_directory(paths[i])) { + const auto& contents = dir_contents[paths[i]]; + for (size_t j = 0; j < contents.size(); ++j) { + bool is_last_child = (j == contents.size() - 1); + std::string child_line = is_last ? " " : "│ "; + child_line += is_last_child ? "└── " : "├── "; - std::string next_prefix = prefix; - if (!prefix.empty()) { - next_prefix += is_last ? " " : "│ "; + std::string child_name = contents[j].filename().string(); + if (fs::is_directory(contents[j])) { + child_name += "/"; } - - std::vector next_is_last_stack = is_last_stack; - next_is_last_stack.push_back(is_last); - - build_tree(rel_path, next_prefix, next_is_last_stack); + child_line += child_name; + result.push_back(child_line); } } - }; - - // Start building the tree from the root - std::vector is_last_stack; - build_tree("/", "", is_last_stack); + } } catch (const fs::filesystem_error& e) { throw std::runtime_error("Failed to access directory: " + std::string(e.what())); @@ -286,6 +211,7 @@ std::vector TreeStructurer::get_directory_structure(const std::stri return result; } + // ----------------------------------------------------------------------------- // Structure Creation from a Tree-like File or String // -----------------------------------------------------------------------------